DataMapperのdm-migrationsのマイグレーションファイルの通し番号は重複していても問題ない
dm-migrations-1.2.0の話です。
dm-railsで次のようにdm-migrationsのマイグレーションファイルを生成すると、001から始まる通し番号のマイグレーションファイルが作成されます。
$ bundle exec rails generate migration create_users invoke data_mapper create db/migrate/001_create_users.rb
複数人で開発を行なっていると、データベースのマイグレーションスクリプトの番号が衝突しがちです。これは困ったなーとはじめのうちは通し番号の調整を行なっていたのですが、無駄な作業だという事がわかりました。
dm-migrationsのマイグレーション情報の管理方法
マイグレーションの適用状況を管理するテーブルmigration_infoのテーブル定義は次の通りです。
CREATE TABLE `migration_info` ( `migration_name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, UNIQUE KEY `migration_name` (`migration_name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
migration_name、名前の方しか管理していません。実は通し番号はおまけで、名前が重要なのでした。
通し番号が重複した場合どうなるのか。
実際に重複している場合の動作を確認してみます。次のようなファイルを用意した場合のマイグレーションの適用状況を考えます。
- db/migrate/001_create_users.rb
# -*- coding: utf-8 -*- migration 1, :create_users do up do create_table :users do column :id, Integer, serial: true column :name, String column :created_at, DateTime column :updated_at, DateTime end end down do drop_table :users end end
- db/migrate/002_create_categories.rb
# -*- coding: utf-8 -*- migration 2, :create_categories do up do create_table :categories do column :id, Integer, serial: true column :name, String, size: 20, not_null: true column :created_at, DateTime column :updated_at, DateTime end end down do drop_table :categories end end
- db/migrate/002_create_movies.rb
# -*- coding: utf-8 -*- migration 2, :create_movies do up do create_table :movies do column :id, Integer, serial: true column :title, String, size: 255, not_null: true column :released_on, Date column :imdb_url, String, size: 255 column :created_at, DateTime column :updated_at, DateTime end end down do drop_table :movies end end
- db/migrate/003_create_category_movies.rb
# -*- coding: utf-8 -*- migration 3, :create_category_movies do up do create_table :category_movies do column :category_id, Integer, primary_key: true column :movie_id, Integer, primary_key: true end # auto_migrateではdm-constraintsの機能でFK制約が作成されるが # db-migrationsからその機能は利用できない。 create_index :category_movies, :category_id create_index :category_movies, :movie_id end down do drop_table :category_movies end end
bundle exec rake db:migrate
マイグレーションを実行してみましょう。
$ bundle exec rake db:migrate == Performing Up Migration #1: create_users CREATE TABLE `users` (`id` SERIAL PRIMARY KEY, `name` VARCHAR(50), `created_at` DATETIME, `updated_at` DATETIME) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT='' -> 0.1809s -> 0.1855s == Performing Up Migration #2: create_categories CREATE TABLE `categories` (`id` SERIAL PRIMARY KEY, `name` VARCHAR(20), `created_at` DATETIME, `updated_at` DATETIME) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT='' -> 0.2658s -> 0.2682s == Performing Up Migration #2: create_movies CREATE TABLE `movies` (`id` SERIAL PRIMARY KEY, `title` VARCHAR(255), `released_on` DATE, `imdb_url` VARCHAR(255), `created_at` DATETIME, `updated_at` DATETIME) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT='' -> 0.1742s -> 0.1772s == Performing Up Migration #3: create_category_movies CREATE TABLE `category_movies` (`category_id` INTEGER, `movie_id` INTEGER) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT='' -> 0.1572s CREATE INDEX `index_category_movies_category_id` ON `category_movies` (`category_id`) -> 0.1088s CREATE INDEX `index_category_movies_movie_id` ON `category_movies` (`movie_id`) -> 0.1344s -> 0.4025s
全部適用されます。migration_infoは次のとおり。
> select * from migration_info; +------------------------+ | migration_name | +------------------------+ | create_categories | | create_category_movies | | create_movies | | create_users | +------------------------+ 4 rows in set (0.00 sec)
bundle exec rake 'db:migrate:down[1]'
マイグレーションの状態を1に戻してみましょう
$ bundle exec rake 'db:migrate:down[1]' == Performing Down Migration #3: create_category_movies DROP TABLE `category_movies` -> 0.0310s -> 0.0312s == Performing Down Migration #2: create_movies DROP TABLE `movies` -> 0.0678s -> 0.0679s == Performing Down Migration #2: create_categories DROP TABLE `categories` -> 0.0429s -> 0.0430s
2が両方とも外されました。migration_infoは次のとおり。
> select * from migration_info; +-------------------+ | migration_name | +-------------------+ | create_users | +-------------------+ 1 rows in set (0.00 sec)
bundle exec rake 'db:migrate:up[2]'
2だけ適応してみましょう。
$ bundle exec rake 'db:migrate:up[2]' == Performing Up Migration #2: create_categories CREATE TABLE `categories` (`id` SERIAL PRIMARY KEY, `name` VARCHAR(20), `created_at` DATETIME, `updated_at` DATETIME) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT='' -> 0.1353s -> 0.1442s == Performing Up Migration #2: create_movies CREATE TABLE `movies` (`id` SERIAL PRIMARY KEY, `title` VARCHAR(255), `released_on` DATE, `imdb_url` VARCHAR(255), `created_at` DATETIME, `updated_at` DATETIME) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT='' -> 0.1231s -> 0.1254s
両方とも適用されました。migration_infoは次のとおり。
> select * from migration_info; +-------------------+ | migration_name | +-------------------+ | create_categories | | create_movies | | create_users | +-------------------+ 3 rows in set (0.00 sec)
名前が重複していた場合どうなるか。
名前が重複したケースも試してみましょう。
$ cp db/migrate/003_create_category_movies.rb db/migrate/004_create_category_movies.rb % bundle exec rake db:migrate rake aborted! Migration name conflict: 'create_category_movies' /home/troter/.rvm/gems/ruby-1.9.3-p327/gems/dm-migrations-1.2.0/lib/dm-migrations/migration_runner.rb:43:in `migration' db/migrate/004_create_category_movies.rb:3:in `<top (required)>' /home/troter/.rvm/gems/ruby-1.9.3-p327/gems/activesupport-3.2.13/lib/active_support/dependencies.rb:245:in `load' # ------------ 省略
コンフリクトという事でエラーになりました。