ActiveRecord to DataMapper/CouchDB class header script

I hacked together this script which dumps the structure of your database into a DataMapper-compatible class header file. You’ll need these for your Models if you’re planning on playing around with datamapper - should save you a bit of typing.

There’s a bit of CouchDB boilerplate in there, feel free to strip that out if you’re not using that. The large sql_type case statement just covered what I had, which was mostly postgres and will need modification for MySQL - but it will tell you what you need to change, should be obvious enough. Note that I am coercing pretty much everything to basic Integer/String - this is for CouchDB but you can change it to match the types you want. And yes, I know it’s ugly!

# datamapper_dump.rake
# Sho Fukamachi 2008
# place in lib/tasks and run with: rake db_to_dm
 
def tables_we_want
  skip_tables = ["schema_info", "sessions"] # this is slow enough as is without sessions
  ActiveRecord::Base.establish_connection
  #ActiveRecord::Base.connection.schema_search_path = "path1, path2" - uncomment for PGSQL
  ActiveRecord::Base.connection.tables - skip_tables
end
 
task :db_to_dm => :environment do
 
  sql  = "SELECT * FROM %s"
  dir = RAILS_ROOT + '/db/dm_temp/'
  FileUtils.mkdir_p(dir)
  FileUtils.chdir(dir)
 
  ActiveRecord::Base.establish_connection
  #ActiveRecord::Base.connection.schema_search_path = "path1, path2" - uncomment for PGSQL
 
  puts "Dumping Schema into DM format..."
 
  File.open("models.rb", "w+") do |file|
    file.write "# Models dump File for DataMapper/CouchDB\n"
    file.write "# Sho Fukamachi 2008\n"
    file.write "\n"
    tables_we_want.each do |table_name|
    class_header = <<-EOF
class #{table_name.singularize.capitalize}
 
  include DataMapper::Resource
 
  def self.default_repository_name
    :couchdb
  end
 
  # required for CouchDB
  property :id, String, :key => true, :field => :_id
  property :rev, String, :field => :_rev
 
  # regular properties
EOF
    file.write class_header
    ActiveRecord::Base.connection.columns(table_name).each do |c|
      if !c.sql_type.scan('integer').empty?
        file.write "  property :#{c.name}, Integer\n"
      elsif !c.sql_type.scan('character').empty?
        file.write "  property :#{c.name}, String\n"
      elsif !c.sql_type.scan('text').empty?
        file.write "  property :#{c.name}, Text\n"
      elsif !c.sql_type.scan('datetime').empty?
        file.write "  property :#{c.name}, DateTime\n"
      elsif !c.sql_type.scan('uuid').empty?
        file.write "  property :#{c.name}, String\n"
      elsif !c.sql_type.scan('boolean').empty?
        file.write "  property :#{c.name}, Integer\n"
      elsif !c.sql_type.scan('double precision').empty?
        file.write "  property :#{c.name}, Integer\n"
      elsif !c.sql_type.scan('bigint').empty?
        file.write "  property :#{c.name}, Integer\n"
      elsif !c.sql_type.scan('smallint').empty?
        file.write "  property :#{c.name}, Integer\n"
      elsif !c.sql_type.scan('date').empty?
        file.write "  property :#{c.name}, Date\n"
      elsif !c.sql_type.scan('timestamp without time zone').empty?
        file.write "  property :#{c.name}, DateTime\n"
      elsif !c.sql_type.scan('time without time zone').empty?
        file.write "  property :#{c.name}, Time\n"
      elsif !c.sql_type.scan('bytea').empty?
        puts "INVALID: column #{c.name} in #{table_name.capitalize}: binary data is not allowed here."
        puts 'You will need to rethink your schema for use in CouchDB. Hint: Attachments.'
        puts 'SKIPPING!'
      else
        file.write "COLUMN: #{c.name}, UNKNOWN DATA TYPE #{c.sql_type} - CHANGE ME!\n"
      end
    end
    file.write "end\n"
    file.write "\n"
    end
  end
  puts "dump succeeded. Look in db/dm_temp/models.rb"
end

Tags: , ,

Leave a Reply