diff --git a/Gemfile b/Gemfile index c5d75ca..f3df1c8 100644 --- a/Gemfile +++ b/Gemfile @@ -7,7 +7,7 @@ gemspec SOURCE = ENV.fetch('SOURCE', :git).to_sym REPO_POSTFIX = SOURCE == :path ? '' : '.git' DATAMAPPER = SOURCE == :path ? Pathname(__FILE__).dirname.parent : 'http://github.com/datamapper' -DM_VERSION = '~> 1.3.0.beta' +DM_VERSION = '>= 1.2.0' DO_VERSION = '~> 0.10.6' DM_DO_ADAPTERS = %w[ sqlite postgres mysql oracle sqlserver ] CURRENT_BRANCH = ENV.fetch('GIT_BRANCH', 'master') diff --git a/README.rdoc b/README.rdoc index d2ee9d7..b811cc1 100644 --- a/README.rdoc +++ b/README.rdoc @@ -2,6 +2,16 @@ DataMapper plugin for writing and specing migrations. +- Foreign Keys support: +- foreign_key_exists? table_name, foreign_key +- table_exists? table +- table_column_exists? table, column +- enable_foreign_key_checks +- disable_foreign_key_checks + + + + == Example require 'dm-migrations/migration_runner' @@ -13,14 +23,30 @@ DataMapper plugin for writing and specing migrations. migration 1, :create_people_table do up do + # Check if table exists + if table_exists? :positions + create_table :jobs do + column :id, Integer, :serial => true + column :name, String + end + end create_table :people do column :id, Integer, :serial => true column :desc, String + column :job_id + end + if table_column_exists? :people, :jobs_id + modify_table :people do + add_foreign_key :job_id, :jobs + end end end down do + disable_foreign_key_checks drop_table :people + drop_table :jobs + enable_foreign_key_checks end end @@ -30,6 +56,8 @@ DataMapper plugin for writing and specing migrations. # You currently have to use the underlying DB type here, rather than # a DataMapper type change_column :desc, 'text' + + drop_foreign_key :job_id, :jobs end end end diff --git a/dm-migrations.gemspec b/dm-migrations.gemspec index 725ee44..581b8f9 100644 --- a/dm-migrations.gemspec +++ b/dm-migrations.gemspec @@ -16,7 +16,7 @@ Gem::Specification.new do |gem| gem.require_paths = [ "lib" ] gem.version = DataMapper::Migrations::VERSION - gem.add_runtime_dependency('dm-core', '~> 1.3.0.beta') + gem.add_runtime_dependency('dm-core', '>= 1.2.0') gem.add_development_dependency('rake', '~> 0.9.2') gem.add_development_dependency('rspec', '~> 1.3.2') diff --git a/lib/dm-migrations/migration.rb b/lib/dm-migrations/migration.rb index f1a7aa4..d92c668 100644 --- a/lib/dm-migrations/migration.rb +++ b/lib/dm-migrations/migration.rb @@ -157,7 +157,15 @@ def select(sql, *bind_values) adapter.select(sql, *bind_values) end end - + + def disable_foreign_key_checks + execute "SET foreign_key_checks = 0" + end + + def enable_foreign_key_checks + execute "SET foreign_key_checks = 1" + end + def create_table(table_name, opts = {}, &block) execute TableCreator.new(adapter, table_name, opts, &block).to_sql end @@ -247,6 +255,14 @@ def quoted_name def migration_info_table_exists? adapter.storage_exists?('migration_info') end + + def table_exists? name + adapter.storage_exists?(name.to_s) + end + + def table_column_exists? table, column + adapter.field_exists?(table.to_s, column.to_s) + end # Fetch the record for this migration out of the migration_info table def migration_record diff --git a/lib/dm-migrations/sql/table_modifier.rb b/lib/dm-migrations/sql/table_modifier.rb index 51598a0..5a3950a 100644 --- a/lib/dm-migrations/sql/table_modifier.rb +++ b/lib/dm-migrations/sql/table_modifier.rb @@ -19,6 +19,29 @@ def add_column(name, type, opts = {}) @statements << "ALTER TABLE #{quoted_table_name} ADD COLUMN #{column.to_sql}" end + def foreign_key_exists?(constraint_name) + # TODO: Move to ADAPTERS + str = "SELECT TRUE FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_TYPE = 'FOREIGN KEY' AND TABLE_SCHEMA = '#{adapter.schema_name}' AND TABLE_NAME = '#{table_name}' AND CONSTRAINT_NAME = '#{@table_name+'_'+constraint_name.to_s.gsub('_id', '')+'_fk'}'" + # puts str + result = @adapter.select(str) + # puts "Result: #{result.inspect}" + result.blank? ? false : (result.first == 1) + end + + def add_foreign_key(column, reference, reference_id = 'id') + @statements << "ALTER TABLE #{quoted_table_name} " + + "ADD CONSTRAINT #{quote_column_name(@table_name+'_'+reference.to_s.gsub('_id', '')+'_fk')} " + + "FOREIGN KEY (#{quote_column_name(column)}) " + + "REFERENCES #{quote_column_name(reference)} (#{quote_column_name(reference_id)}) " + + "ON DELETE NO ACTION ON UPDATE NO ACTION" + end + + def drop_foreign_key(constraint_name) + fk_name = quote_column_name(@table_name+'_'+constraint_name.to_s.gsub('_id', '')+'_fk') + @statements << "ALTER TABLE #{quoted_table_name} DROP FOREIGN KEY #{fk_name}" + # @statements << "ALTER TABLE #{quoted_table_name} DROP INDEX #{fk_name}" + end + def drop_column(name) # raise NotImplemented for SQLite3. Can't ALTER TABLE, need to copy table. # We'd have to inspect it, and we can't, since we aren't executing any queries yet. diff --git a/lib/dm-migrations/version.rb b/lib/dm-migrations/version.rb index e725aea..a193e2a 100644 --- a/lib/dm-migrations/version.rb +++ b/lib/dm-migrations/version.rb @@ -1,5 +1,5 @@ module DataMapper module Migrations - VERSION = '1.3.0.beta' + VERSION = '1.3.3' end end