| 1 | #
 | 
  
    | 2 | # Convert/transfer data from production => development.    This facilitates
 | 
  
    | 3 | # a conversion one database adapter type to another (say postgres -> mysql )
 | 
  
    | 4 | #
 | 
  
    | 5 | # WARNING 1: this script deletes all development data and replaces it with
 | 
  
    | 6 | #                     production data
 | 
  
    | 7 | #
 | 
  
    | 8 | # WARNING 2: This script assumes it is the only user updating either database.
 | 
  
    | 9 | #                     Database integrity could be corrupted if other users where 
 | 
  
    | 10 | #                     writing to the databases.
 | 
  
    | 11 | #
 | 
  
    | 12 | # Usage:  rake db:convert:prod2dev
 | 
  
    | 13 | #
 | 
  
    | 14 | # It assumes the development database has a schema identical to the production 
 | 
  
    | 15 | # database, but will delete any data before importing the production data
 | 
  
    | 16 | #
 | 
  
    | 17 | # A couple of refinements added to Rama's script by M.Taylor:
 | 
  
    | 18 | #    * Suppress single-table inheritance behaviour for tables containing a column named "type"
 | 
  
    | 19 | #    * Do not copy column id if the table doesn't have one.
 | 
  
    | 20 | #
 | 
  
    | 21 | # A couple of the outer loops evolved from 
 | 
  
    | 22 | #    http://snippets.dzone.com/posts/show/3393
 | 
  
    | 23 | #
 | 
  
    | 24 | # For further instructions see 
 | 
  
    | 25 | #    http://myutil.com/2008/8/31/rake-task-transfer-rails-database-mysql-to-postgres
 | 
  
    | 26 | #
 | 
  
    | 27 | # The master repository for this script is at github:
 | 
  
    | 28 | #    http://github.com/face/rails_db_convert_using_adapters/tree/master
 | 
  
    | 29 | #
 | 
  
    | 30 | #
 | 
  
    | 31 | # Author: Rama McIntosh
 | 
  
    | 32 | #         Matson Systems, Inc.
 | 
  
    | 33 | #         http://www.matsonsystems.com
 | 
  
    | 34 | #
 | 
  
    | 35 | # This rake task is released under this BSD license:
 | 
  
    | 36 | #
 | 
  
    | 37 | # Copyright (c) 2008, Matson Systems, Inc. All rights reserved.
 | 
  
    | 38 | # 
 | 
  
    | 39 | # Redistribution and use in source and binary forms, with or without
 | 
  
    | 40 | # modification, are permitted provided that the following conditions
 | 
  
    | 41 | # are met:
 | 
  
    | 42 | # 
 | 
  
    | 43 | # * Redistributions of source code must retain the above copyright
 | 
  
    | 44 | #   notice, this list of conditions and the following disclaimer.
 | 
  
    | 45 | # * Redistributions in binary form must reproduce the above copyright
 | 
  
    | 46 | #   notice, this list of conditions and the following disclaimer in the
 | 
  
    | 47 | #   documentation and/or other materials provided with the distribution.
 | 
  
    | 48 | # * Neither the name of Matson Systems, Inc. nor the names of its
 | 
  
    | 49 | #   contributors may be used to endorse or promote products derived
 | 
  
    | 50 | #   from this software without specific prior written permission.
 | 
  
    | 51 | #
 | 
  
    | 52 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
  
    | 53 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
  
    | 54 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 | 
  
    | 55 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 | 
  
    | 56 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
  
    | 57 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
  
    | 58 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 | 
  
    | 59 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 | 
  
    | 60 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
  
    | 61 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 | 
  
    | 62 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 | 
  
    | 63 | # POSSIBILITY OF SUCH DAMAGE.
 | 
  
    | 64 | 
 | 
  
    | 65 | # PAGE_SIZE is the number of rows updated in a single transaction.
 | 
  
    | 66 | # This facilitates tables where the number of rows exceeds the systems
 | 
  
    | 67 | # memory
 | 
  
    | 68 | PAGE_SIZE=10000
 | 
  
    | 69 | 
 | 
  
    | 70 | namespace :db do
 | 
  
    | 71 |   namespace :convert do    
 | 
  
    | 72 |     desc 'Convert/import production data to development.   DANGER Deletes all data in the development database.   Assumes both schemas are already migrated.'
 | 
  
    | 73 |     task :prod2dev => :environment do
 | 
  
    | 74 | 
 | 
  
    | 75 |       # We need unique classes so ActiveRecord can hash different connections
 | 
  
    | 76 |       # We do not want to use the real Model classes because any business
 | 
  
    | 77 |       # rules will likely get in the way of a database transfer
 | 
  
    | 78 |       class ProductionModelClass < ActiveRecord::Base
 | 
  
    | 79 |         self.inheritance_column = :_type_disabled
 | 
  
    | 80 |       end
 | 
  
    | 81 |       class DevelopmentModelClass < ActiveRecord::Base
 | 
  
    | 82 |         self.inheritance_column = :_type_disabled
 | 
  
    | 83 |       end
 | 
  
    | 84 | 
 | 
  
    | 85 |       skip_tables = ["schema_info", "schema_migrations"]
 | 
  
    | 86 |       
 | 
  
    | 87 |       # Generate a list of all tables needing conversion
 | 
  
    | 88 |       table_list = (ActiveRecord::Base.connection.tables - skip_tables).sort
 | 
  
    | 89 |     
 | 
  
    | 90 |       # Use this line to convert just a specific list of tables   
 | 
  
    | 91 |       # table_list = ["custom_fields_trackers","custom_fields_projects","groups_users","projects_trackers"]
 | 
  
    | 92 |       
 | 
  
    | 93 |       ActiveRecord::Base.establish_connection(:production)
 | 
  
    | 94 | 
 | 
  
    | 95 |       table_list.each do |table_name|
 | 
  
    | 96 |  
 | 
  
    | 97 |         ProductionModelClass.set_table_name(table_name)
 | 
  
    | 98 |         DevelopmentModelClass.set_table_name(table_name)
 | 
  
    | 99 |         DevelopmentModelClass.establish_connection(:development)
 | 
  
    | 100 |         DevelopmentModelClass.reset_column_information
 | 
  
    | 101 |         ProductionModelClass.reset_column_information
 | 
  
    | 102 |         DevelopmentModelClass.record_timestamps = false
 | 
  
    | 103 | 
 | 
  
    | 104 |         # Page through the data in case the table is too large to fit in RAM
 | 
  
    | 105 |         offset = count = 0;
 | 
  
    | 106 |         print "Converting #{table_name}..."; STDOUT.flush
 | 
  
    | 107 |         # First, delete any old dev data
 | 
  
    | 108 |         DevelopmentModelClass.delete_all
 | 
  
    | 109 |         while ((models = ProductionModelClass.find(:all, 
 | 
  
    | 110 |             :offset=>offset, :limit=>PAGE_SIZE)).size > 0)
 | 
  
    | 111 | 
 | 
  
    | 112 |           count += models.size
 | 
  
    | 113 |           offset += PAGE_SIZE
 | 
  
    | 114 | 
 | 
  
    | 115 |           # Now, write out the prod data to the dev db
 | 
  
    | 116 |           DevelopmentModelClass.transaction do
 | 
  
    | 117 |             models.each do |model|
 | 
  
    | 118 |               new_model = DevelopmentModelClass.new(model.attributes)
 | 
  
    | 119 |               if (model.attributes.has_key?('id'))
 | 
  
    | 120 |                 new_model.id = model.id
 | 
  
    | 121 |               end
 | 
  
    | 122 |               new_model.save(false)
 | 
  
    | 123 |             end
 | 
  
    | 124 |           end
 | 
  
    | 125 |         end
 | 
  
    | 126 |         print "#{count} records converted\n"
 | 
  
    | 127 |       end
 | 
  
    | 128 |     end
 | 
  
    | 129 |   end
 | 
  
    | 130 | end
 |