sbf-dm-migrations 1.3.0.beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +38 -0
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +468 -0
  5. data/.travis.yml +52 -0
  6. data/Gemfile +61 -0
  7. data/LICENSE +20 -0
  8. data/README.rdoc +39 -0
  9. data/Rakefile +4 -0
  10. data/db/migrations/1_create_people_table.rb +12 -0
  11. data/db/migrations/2_add_dob_to_people.rb +13 -0
  12. data/db/migrations/config.rb +4 -0
  13. data/dm-migrations.gemspec +20 -0
  14. data/examples/Rakefile +149 -0
  15. data/examples/sample_migration.rb +58 -0
  16. data/examples/sample_migration_spec.rb +46 -0
  17. data/lib/dm-migrations/adapters/dm-do-adapter.rb +304 -0
  18. data/lib/dm-migrations/adapters/dm-mysql-adapter.rb +306 -0
  19. data/lib/dm-migrations/adapters/dm-oracle-adapter.rb +339 -0
  20. data/lib/dm-migrations/adapters/dm-postgres-adapter.rb +152 -0
  21. data/lib/dm-migrations/adapters/dm-sqlite-adapter.rb +88 -0
  22. data/lib/dm-migrations/adapters/dm-sqlserver-adapter.rb +184 -0
  23. data/lib/dm-migrations/adapters/dm-yaml-adapter.rb +21 -0
  24. data/lib/dm-migrations/auto_migration.rb +227 -0
  25. data/lib/dm-migrations/exceptions/duplicate_migration.rb +6 -0
  26. data/lib/dm-migrations/migration.rb +323 -0
  27. data/lib/dm-migrations/migration_runner.rb +76 -0
  28. data/lib/dm-migrations/sql/column.rb +5 -0
  29. data/lib/dm-migrations/sql/mysql.rb +84 -0
  30. data/lib/dm-migrations/sql/oracle.rb +9 -0
  31. data/lib/dm-migrations/sql/postgres.rb +89 -0
  32. data/lib/dm-migrations/sql/sqlite.rb +59 -0
  33. data/lib/dm-migrations/sql/sqlserver.rb +9 -0
  34. data/lib/dm-migrations/sql/table.rb +15 -0
  35. data/lib/dm-migrations/sql/table_creator.rb +105 -0
  36. data/lib/dm-migrations/sql/table_modifier.rb +57 -0
  37. data/lib/dm-migrations/sql.rb +7 -0
  38. data/lib/dm-migrations/version.rb +5 -0
  39. data/lib/dm-migrations.rb +3 -0
  40. data/lib/spec/example/migration_example_group.rb +69 -0
  41. data/lib/spec/matchers/migration_matchers.rb +96 -0
  42. data/spec/integration/auto_migration_spec.rb +590 -0
  43. data/spec/integration/auto_upgrade_spec.rb +41 -0
  44. data/spec/integration/migration_runner_spec.rb +84 -0
  45. data/spec/integration/migration_spec.rb +156 -0
  46. data/spec/integration/sql_spec.rb +290 -0
  47. data/spec/isolated/require_after_setup_spec.rb +24 -0
  48. data/spec/isolated/require_before_setup_spec.rb +24 -0
  49. data/spec/isolated/require_spec.rb +23 -0
  50. data/spec/spec_helper.rb +16 -0
  51. data/spec/unit/migration_spec.rb +501 -0
  52. data/spec/unit/sql/column_spec.rb +14 -0
  53. data/spec/unit/sql/postgres_spec.rb +90 -0
  54. data/spec/unit/sql/sqlite_extensions_spec.rb +103 -0
  55. data/spec/unit/sql/table_creator_spec.rb +91 -0
  56. data/spec/unit/sql/table_modifier_spec.rb +47 -0
  57. data/spec/unit/sql/table_spec.rb +26 -0
  58. data/spec/unit/sql_spec.rb +7 -0
  59. data/tasks/spec.rake +21 -0
  60. data/tasks/yard.rake +9 -0
  61. data/tasks/yardstick.rake +19 -0
  62. metadata +120 -0
@@ -0,0 +1,152 @@
1
+ require 'dm-migrations/auto_migration'
2
+ require 'dm-migrations/adapters/dm-do-adapter'
3
+
4
+ module DataMapper
5
+ module Migrations
6
+ module PostgresAdapter
7
+ include SQL, DataObjectsAdapter
8
+
9
+ # @api private
10
+ def self.included(base)
11
+ base.extend DataObjectsAdapter::ClassMethods
12
+ base.extend ClassMethods
13
+ end
14
+
15
+ # @api semipublic
16
+ def upgrade_model_storage(model)
17
+ without_notices { super }
18
+ end
19
+
20
+ # @api semipublic
21
+ def create_model_storage(model)
22
+ without_notices { super }
23
+ end
24
+
25
+ # @api semipublic
26
+ def destroy_model_storage(model)
27
+ if supports_drop_table_if_exists?
28
+ without_notices { super }
29
+ else
30
+ super
31
+ end
32
+ end
33
+
34
+ module SQL # :nodoc:
35
+ # private ## This cannot be private for current migrations
36
+
37
+ # @api private
38
+ def supports_drop_table_if_exists?
39
+ @supports_drop_table_if_exists ||= postgres_version >= '8.2'
40
+ end
41
+
42
+ # @api private
43
+ def schema_name
44
+ @schema_name ||= select('SELECT current_schema()').first.freeze
45
+ end
46
+
47
+ # @api private
48
+ def postgres_version
49
+ @postgres_version ||= select('SELECT version()').first.split[1].freeze
50
+ end
51
+
52
+ # @api private
53
+ def without_notices
54
+ # execute the block with NOTICE messages disabled
55
+ execute('SET client_min_messages = warning')
56
+ yield
57
+ ensure
58
+ execute('RESET client_min_messages')
59
+ end
60
+
61
+ # @api private
62
+ def property_schema_hash(property)
63
+ schema = super
64
+
65
+ # Postgres does not support precision and scale for Float
66
+ if property.is_a?(Property::Float)
67
+ schema.delete(:precision)
68
+ schema.delete(:scale)
69
+ end
70
+
71
+ if property.is_a?(Property::Integer)
72
+ min = property.min
73
+ max = property.max
74
+
75
+ schema[:primitive] = integer_column_statement(min..max) if min && max
76
+ end
77
+
78
+ schema[:primitive] = serial_column_statement(min..max) if schema[:serial]
79
+
80
+ schema
81
+ end
82
+
83
+ # Return SQL statement for the integer column
84
+ #
85
+ # @param [Range] range
86
+ # the min/max allowed integers
87
+ #
88
+ # @return [String]
89
+ # the statement to create the integer column
90
+ #
91
+ # @api private
92
+ private def integer_column_statement(range)
93
+ min = range.first
94
+ max = range.last
95
+
96
+ smallint = 2**15
97
+ integer = 2**31
98
+ bigint = 2**63
99
+
100
+ if min >= -smallint && max < smallint
101
+ 'SMALLINT'
102
+ elsif min >= -integer && max < integer
103
+ 'INTEGER'
104
+ elsif min >= -bigint && max < bigint
105
+ 'BIGINT'
106
+ else
107
+ raise ArgumentError, "min #{min} and max #{max} exceeds supported range"
108
+ end
109
+ end
110
+
111
+ # Return SQL statement for the serial column
112
+ #
113
+ # @param [Range] range
114
+ # the range of allowed integers
115
+ #
116
+ # @return [String]
117
+ # the statement to create the serial column
118
+ #
119
+ # @api private
120
+ private def serial_column_statement(range)
121
+ max = range.last
122
+
123
+ if max.nil? || max < 2**31
124
+ 'SERIAL'
125
+ elsif max < 2**63
126
+ 'BIGSERIAL'
127
+ else
128
+ raise ArgumentError, "min #{range.first} and max #{max} exceeds supported range"
129
+ end
130
+ end
131
+ end
132
+
133
+ module ClassMethods
134
+ # Types for PostgreSQL databases.
135
+ #
136
+ # @return [Hash] types for PostgreSQL databases.
137
+ #
138
+ # @api private
139
+ def type_map
140
+ precision = Property::Numeric.precision
141
+ scale = Property::Decimal.scale
142
+
143
+ super.merge(
144
+ Property::Binary => {primitive: 'BYTEA'},
145
+ BigDecimal => {primitive: 'NUMERIC', precision: precision, scale: scale},
146
+ Float => {primitive: 'DOUBLE PRECISION'}
147
+ ).freeze
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,88 @@
1
+ require 'dm-migrations/auto_migration'
2
+ require 'dm-migrations/adapters/dm-do-adapter'
3
+
4
+ module DataMapper
5
+ module Migrations
6
+ module SqliteAdapter
7
+ include SQL, DataObjectsAdapter
8
+
9
+ # @api private
10
+ def self.included(base)
11
+ base.extend DataObjectsAdapter::ClassMethods
12
+ base.extend ClassMethods
13
+ end
14
+
15
+ # @api semipublic
16
+ def storage_exists?(storage_name)
17
+ table_info(storage_name).any?
18
+ end
19
+
20
+ # @api semipublic
21
+ def field_exists?(storage_name, column_name)
22
+ table_info(storage_name).any? do |row|
23
+ row.name == column_name
24
+ end
25
+ end
26
+
27
+ module SQL # :nodoc:
28
+ # private ## This cannot be private for current migrations
29
+
30
+ # @api private
31
+ def supports_serial?
32
+ @supports_serial ||= sqlite_version >= '3.1.0'
33
+ end
34
+
35
+ # @api private
36
+ def supports_drop_table_if_exists?
37
+ @supports_drop_table_if_exists ||= sqlite_version >= '3.3.0'
38
+ end
39
+
40
+ # @api private
41
+ def table_info(table_name)
42
+ select("PRAGMA table_info(#{quote_name(table_name)})")
43
+ end
44
+
45
+ # @api private
46
+ def create_table_statement(connection, model, properties)
47
+ statement = DataMapper::Ext::String.compress_lines(<<-SQL)
48
+ CREATE TABLE #{quote_name(model.storage_name(name))}
49
+ (#{properties.map { |property| property_schema_statement(connection, property_schema_hash(property)) }.join(', ')}
50
+ SQL
51
+
52
+ # skip adding the primary key if one of the columns is serial. In
53
+ # SQLite the serial column must be the primary key, so it has already
54
+ # been defined
55
+ statement << ", PRIMARY KEY(#{properties.key.map { |property| quote_name(property.field) }.join(', ')})" unless properties.any?(&:serial?)
56
+
57
+ statement << ')'
58
+ statement
59
+ end
60
+
61
+ # @api private
62
+ def property_schema_statement(connection, schema)
63
+ statement = super
64
+
65
+ statement << ' PRIMARY KEY AUTOINCREMENT' if supports_serial? && schema[:serial]
66
+
67
+ statement
68
+ end
69
+
70
+ # @api private
71
+ def sqlite_version
72
+ @sqlite_version ||= select('SELECT sqlite_version(*)').first.freeze
73
+ end
74
+ end
75
+
76
+ module ClassMethods
77
+ # Types for SQLite 3 databases.
78
+ #
79
+ # @return [Hash] types for SQLite 3 databases.
80
+ #
81
+ # @api private
82
+ def type_map
83
+ super.merge(Class => {primitive: 'VARCHAR'}).freeze
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,184 @@
1
+ require 'dm-migrations/auto_migration'
2
+ require 'dm-migrations/adapters/dm-do-adapter'
3
+
4
+ module DataMapper
5
+ module Migrations
6
+ module SqlserverAdapter
7
+ DEFAULT_CHARACTER_SET = 'utf8'.freeze
8
+
9
+ include SQL, DataObjectsAdapter
10
+
11
+ # @api private
12
+ def self.included(base)
13
+ base.extend DataObjectsAdapter::ClassMethods
14
+ base.extend ClassMethods
15
+ end
16
+
17
+ # @api semipublic
18
+ def storage_exists?(storage_name)
19
+ select('SELECT name FROM sysobjects WHERE name LIKE ?', storage_name).first == storage_name
20
+ end
21
+
22
+ # @api semipublic
23
+ def field_exists?(storage_name, field_name)
24
+ result = select(
25
+ 'SELECT c.name FROM sysobjects as o JOIN syscolumns AS c ON o.id = c.id WHERE o.name = ? AND c.name LIKE ?',
26
+ storage_name,
27
+ field_name
28
+ ).first
29
+ result ? result.to_s == field_name.to_s : false
30
+ end
31
+
32
+ module SQL # :nodoc:
33
+ # private ## This cannot be private for current migrations
34
+
35
+ # @api private
36
+ def supports_serial?
37
+ true
38
+ end
39
+
40
+ # @api private
41
+ def supports_drop_table_if_exists?
42
+ false
43
+ end
44
+
45
+ # @api private
46
+ def schema_name
47
+ select('SELECT DB_NAME()')
48
+ end
49
+
50
+ # TODO: update dkubb/dm-more/dm-migrations to use schema_name and remove this
51
+
52
+ alias_method :db_name, :schema_name
53
+
54
+ # @api private
55
+ def create_table_statement(connection, model, properties)
56
+ statement = DataMapper::Ext::String.compress_lines(<<-SQL)
57
+ CREATE TABLE #{quote_name(model.storage_name(name))}
58
+ (#{properties.map { |property| property_schema_statement(connection, property_schema_hash(property)) }.join(', ')}
59
+ SQL
60
+
61
+ # specific the primary keys.
62
+ # don't have to filter out Serial (aka IDENTITY) type
63
+ statement << ", PRIMARY KEY(#{properties.key.map { |property| quote_name(property.field) }.join(', ')})"
64
+
65
+ statement << ')'
66
+ statement
67
+ end
68
+
69
+ # @api private
70
+ def property_schema_hash(property)
71
+ schema = super
72
+
73
+ if property.is_a?(Property::Integer)
74
+ min = property.min
75
+ max = property.max
76
+
77
+ schema[:primitive] = integer_column_statement(min..max) if min && max
78
+ end
79
+
80
+ schema_primitive = schema[:primitive]
81
+
82
+ if schema_primitive == 'NVARCHAR'
83
+ schema[:length] = if property.length <= 4000
84
+ property.length
85
+ else
86
+ 'max'
87
+ end
88
+ end
89
+
90
+ schema.delete(:default) if schema[:primitive] == 'TEXT'
91
+
92
+ schema
93
+ end
94
+
95
+ # @api private
96
+ def property_schema_statement(connection, schema)
97
+ if supports_serial? && schema[:serial]
98
+ statement = quote_name(schema[:name])
99
+ statement << " #{schema[:primitive]}"
100
+
101
+ length = schema[:length]
102
+
103
+ if schema[:precision] && schema[:scale]
104
+ statement << "(#{%i(precision scale).map { |key| connection.quote_value(schema[key]) }.join(', ')})"
105
+ elsif length
106
+ statement << "(#{connection.quote_value(length)})"
107
+ end
108
+
109
+ statement << ' IDENTITY'
110
+ else
111
+ statement = super
112
+ end
113
+
114
+ statement
115
+ end
116
+
117
+ # @api private
118
+ def character_set
119
+ @character_set ||= show_variable('character_set_connection') || DEFAULT_CHARACTER_SET
120
+ end
121
+
122
+ # @api private
123
+ def collation
124
+ @collation ||= show_variable('collation_connection') || DEFAULT_COLLATION
125
+ end
126
+
127
+ # @api private
128
+ def show_variable(_name)
129
+ raise 'SqlserverAdapter#show_variable: Not implemented'
130
+ end
131
+
132
+ # Return SQL statement for the integer column
133
+ #
134
+ # @param [Range] range
135
+ # the min/max allowed integers
136
+ #
137
+ # @return [String]
138
+ # the statement to create the integer column
139
+ #
140
+ # @api private
141
+ private def integer_column_statement(range)
142
+ min = range.first
143
+ max = range.last
144
+
145
+ smallint = 2**15
146
+ integer = 2**31
147
+ bigint = 2**63
148
+
149
+ if min >= 0 && max < 2**8
150
+ 'TINYINT'
151
+ elsif min >= -smallint && max < smallint then 'SMALLINT'
152
+ elsif min >= -integer && max < integer then 'INT'
153
+ elsif min >= -bigint && max < bigint then 'BIGINT'
154
+ else
155
+ raise ArgumentError, "min #{min} and max #{max} exceeds supported range"
156
+ end
157
+ end
158
+ end
159
+
160
+ module ClassMethods
161
+ # Types for Sqlserver databases.
162
+ #
163
+ # @return [Hash] types for Sqlserver databases.
164
+ #
165
+ # @api private
166
+ def type_map
167
+ length = Property::String.length
168
+ _precision = Property::Numeric.precision
169
+ _scale = Property::Decimal.scale
170
+
171
+ super.merge(
172
+ DateTime => {primitive: 'DATETIME'},
173
+ Date => {primitive: 'SMALLDATETIME'},
174
+ Time => {primitive: 'SMALLDATETIME'},
175
+ TrueClass => {primitive: 'BIT'},
176
+ String => {primitive: 'NVARCHAR', length: length},
177
+ Property::Text => {primitive: 'NVARCHAR', length: 'max'},
178
+ Property::Binary => {primitive: 'VARBINARY', length: 'max'}
179
+ ).freeze
180
+ end
181
+ end
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,21 @@
1
+ require 'dm-migrations/auto_migration'
2
+ require 'dm-migrations/adapters/dm-do-adapter'
3
+
4
+ module DataMapper
5
+ module Migrations
6
+ module YamlAdapter
7
+ def self.included(_base)
8
+ DataMapper.extend(Migrations::SingletonMethods)
9
+ %i(Repository Model).each do |name|
10
+ DataMapper.const_get(name).send(:include, Migrations.const_get(name))
11
+ end
12
+ end
13
+
14
+ # @api semipublic
15
+ def destroy_model_storage(model)
16
+ yaml_file(model).unlink if yaml_file(model).file?
17
+ true
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,227 @@
1
+ require 'dm-core'
2
+
3
+ module DataMapper
4
+ module Migrations
5
+ module SingletonMethods
6
+ # destructively migrates the repository upwards to match model definitions
7
+ #
8
+ # @param [Symbol] repository_name repository to act on, :default is the default
9
+ #
10
+ # @api public
11
+ def migrate!(repository_name = nil)
12
+ repository(repository_name).migrate!
13
+ end
14
+
15
+ # drops and recreates the repository upwards to match model definitions
16
+ #
17
+ # @param [Symbol] repository_name repository to act on, :default is the default
18
+ #
19
+ # @api public
20
+ def auto_migrate!(repository_name = nil)
21
+ repository_execute(:auto_migrate!, repository_name)
22
+ end
23
+
24
+ # @api public
25
+ def auto_upgrade!(repository_name = nil)
26
+ repository_execute(:auto_upgrade!, repository_name)
27
+ end
28
+
29
+ # @api semipublic
30
+ private def auto_migrate_down!(repository_name)
31
+ repository_execute(:auto_migrate_down!, repository_name)
32
+ end
33
+
34
+ # @api semipublic
35
+ private def auto_migrate_up!(repository_name)
36
+ repository_execute(:auto_migrate_up!, repository_name)
37
+ end
38
+
39
+ # @api private
40
+ private def repository_execute(method, repository_name)
41
+ models = DataMapper::Model.descendants
42
+ models = models.select { |m| m.repository_name == repository_name } if repository_name
43
+ models.each do |model|
44
+ model.send(method, model.repository_name)
45
+ end
46
+ end
47
+ end
48
+
49
+ module Repository
50
+ # Determine whether a particular named storage exists in this repository
51
+ #
52
+ # @param [String]
53
+ # storage_name name of the storage to test for
54
+ #
55
+ # @return [Boolean]
56
+ # true if the data-store +storage_name+ exists
57
+ #
58
+ # @api semipublic
59
+ def storage_exists?(storage_name)
60
+ adapter = self.adapter
61
+ return false unless adapter.respond_to?(:storage_exists?)
62
+
63
+ adapter.storage_exists?(storage_name)
64
+ end
65
+
66
+ # @api semipublic
67
+ def upgrade_model_storage(model)
68
+ adapter = self.adapter
69
+ return unless adapter.respond_to?(:upgrade_model_storage)
70
+
71
+ adapter.upgrade_model_storage(model)
72
+ end
73
+
74
+ # @api semipublic
75
+ def create_model_storage(model)
76
+ adapter = self.adapter
77
+ return unless adapter.respond_to?(:create_model_storage)
78
+
79
+ adapter.create_model_storage(model)
80
+ end
81
+
82
+ # @api semipublic
83
+ def destroy_model_storage(model)
84
+ adapter = self.adapter
85
+ return unless adapter.respond_to?(:destroy_model_storage)
86
+
87
+ adapter.destroy_model_storage(model)
88
+ end
89
+
90
+ # Destructively automigrates the data-store to match the model.
91
+ # First migrates all models down and then up.
92
+ # REPEAT: THIS IS DESTRUCTIVE
93
+ #
94
+ # @api public
95
+ def auto_migrate!
96
+ DataMapper.auto_migrate!(name)
97
+ end
98
+
99
+ # Safely migrates the data-store to match the model
100
+ # preserving data already in the data-store
101
+ #
102
+ # @api public
103
+ def auto_upgrade!
104
+ DataMapper.auto_upgrade!(name)
105
+ end
106
+ end
107
+
108
+ module Model
109
+ # @api private
110
+ def self.included(mod)
111
+ mod.descendants.each { |model| model.extend self }
112
+ end
113
+
114
+ # @api semipublic
115
+ def storage_exists?(repository_name = default_repository_name)
116
+ repository(repository_name).storage_exists?(storage_name(repository_name))
117
+ end
118
+
119
+ # Destructively automigrates the data-store to match the model
120
+ # REPEAT: THIS IS DESTRUCTIVE
121
+ #
122
+ # @param [Symbol] repository_name the repository to be migrated
123
+ #
124
+ # @api public
125
+ def auto_migrate!(repository_name = self.repository_name)
126
+ assert_valid(true)
127
+ auto_migrate_down!(repository_name)
128
+ auto_migrate_up!(repository_name)
129
+ end
130
+
131
+ # Safely migrates the data-store to match the model
132
+ # preserving data already in the data-store
133
+ #
134
+ # @param [Symbol] repository_name the repository to be migrated
135
+ #
136
+ # @api public
137
+ def auto_upgrade!(repository_name = self.repository_name)
138
+ assert_valid(true)
139
+ base_model = self.base_model
140
+ if base_model == self
141
+ repository(repository_name).upgrade_model_storage(self)
142
+ else
143
+ base_model.auto_upgrade!(repository_name)
144
+ end
145
+ end
146
+
147
+ # Destructively migrates the data-store down, which basically
148
+ # deletes all the models.
149
+ # REPEAT: THIS IS DESTRUCTIVE
150
+ #
151
+ # @param [Symbol] repository_name the repository to be migrated
152
+ #
153
+ # @api private
154
+ def auto_migrate_down!(repository_name = self.repository_name)
155
+ assert_valid(true)
156
+ base_model = self.base_model
157
+ if base_model == self
158
+ repository(repository_name).destroy_model_storage(self)
159
+ else
160
+ base_model.auto_migrate_down!(repository_name)
161
+ end
162
+ end
163
+
164
+ # Auto migrates the data-store to match the model
165
+ #
166
+ # @param [Symbol] repository_name the repository to be migrated
167
+ #
168
+ # @api private
169
+ def auto_migrate_up!(repository_name = self.repository_name)
170
+ assert_valid(true)
171
+ base_model = self.base_model
172
+ if base_model == self
173
+ repository(repository_name).create_model_storage(self)
174
+ else
175
+ base_model.auto_migrate_up!(repository_name)
176
+ end
177
+ end
178
+ end
179
+
180
+ def self.include_migration_api
181
+ DataMapper.extend(SingletonMethods)
182
+ %i(Repository Model).each do |name|
183
+ DataMapper.const_get(name).send(:include, const_get(name))
184
+ end
185
+ DataMapper::Model.append_extensions(Model)
186
+ Adapters::AbstractAdapter.descendants.each do |adapter_class|
187
+ Adapters.include_migration_api(DataMapper::Inflector.demodulize(adapter_class.name))
188
+ end
189
+ end
190
+ end
191
+
192
+ module Adapters
193
+ def self.include_migration_api(const_name)
194
+ require auto_migration_extensions(const_name)
195
+ if Migrations.const_defined?(const_name)
196
+ adapter = const_get(const_name)
197
+ adapter.send(:include, migration_module(const_name))
198
+ end
199
+ rescue LoadError
200
+ # Silently ignore the fact that no adapter extensions could be required
201
+ # This means that the adapter in use doesn't support migrations
202
+ end
203
+
204
+ def self.migration_module(const_name)
205
+ Migrations.const_get(const_name)
206
+ end
207
+
208
+ class << self
209
+ # @api private
210
+ private def auto_migration_extensions(const_name)
211
+ name = adapter_name(const_name)
212
+ name = 'do' if name == 'dataobjects'
213
+ "dm-migrations/adapters/dm-#{name}-adapter"
214
+ end
215
+ end
216
+
217
+ extendable do
218
+ # @api private
219
+ def const_added(const_name)
220
+ include_migration_api(const_name)
221
+ super
222
+ end
223
+ end
224
+ end
225
+
226
+ Migrations.include_migration_api
227
+ end
@@ -0,0 +1,6 @@
1
+ module DataMapper
2
+ module Migrations
3
+ class DuplicateMigration < StandardError
4
+ end
5
+ end
6
+ end