dm-migrations 0.10.2 → 1.0.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. data/.gitignore +36 -0
  2. data/Gemfile +141 -0
  3. data/Rakefile +2 -3
  4. data/VERSION +1 -1
  5. data/dm-migrations.gemspec +50 -18
  6. data/lib/dm-migrations.rb +2 -0
  7. data/lib/dm-migrations/adapters/dm-do-adapter.rb +276 -0
  8. data/lib/dm-migrations/adapters/dm-mysql-adapter.rb +283 -0
  9. data/lib/dm-migrations/adapters/dm-oracle-adapter.rb +321 -0
  10. data/lib/dm-migrations/adapters/dm-postgres-adapter.rb +159 -0
  11. data/lib/dm-migrations/adapters/dm-sqlite-adapter.rb +96 -0
  12. data/lib/dm-migrations/adapters/dm-sqlserver-adapter.rb +177 -0
  13. data/lib/dm-migrations/adapters/dm-yaml-adapter.rb +23 -0
  14. data/lib/dm-migrations/auto_migration.rb +238 -0
  15. data/lib/dm-migrations/migration.rb +3 -3
  16. data/lib/dm-migrations/sql.rb +2 -2
  17. data/lib/dm-migrations/sql/mysql.rb +3 -3
  18. data/lib/dm-migrations/sql/{postgresql.rb → postgres.rb} +3 -3
  19. data/lib/dm-migrations/sql/{sqlite3.rb → sqlite.rb} +3 -3
  20. data/spec/integration/auto_migration_spec.rb +506 -0
  21. data/spec/integration/migration_runner_spec.rb +12 -2
  22. data/spec/integration/migration_spec.rb +28 -14
  23. data/spec/integration/sql_spec.rb +22 -21
  24. data/spec/isolated/require_after_setup_spec.rb +30 -0
  25. data/spec/isolated/require_before_setup_spec.rb +30 -0
  26. data/spec/isolated/require_spec.rb +25 -0
  27. data/spec/spec_helper.rb +10 -25
  28. data/spec/unit/migration_spec.rb +320 -319
  29. data/spec/unit/sql/{postgresql_spec.rb → postgres_spec.rb} +17 -17
  30. data/spec/unit/sql/{sqlite3_extensions_spec.rb → sqlite_extensions_spec.rb} +14 -14
  31. data/tasks/local_gemfile.rake +18 -0
  32. data/tasks/spec.rake +0 -3
  33. metadata +72 -32
@@ -0,0 +1,238 @@
1
+ require 'dm-core'
2
+
3
+ module DataMapper
4
+ module Migrations
5
+ module SingletonMethods
6
+
7
+ # destructively migrates the repository upwards to match model definitions
8
+ #
9
+ # @param [Symbol] name repository to act on, :default is the default
10
+ #
11
+ # @api public
12
+ def migrate!(repository_name = nil)
13
+ repository(repository_name).migrate!
14
+ end
15
+
16
+ # drops and recreates the repository upwards to match model definitions
17
+ #
18
+ # @param [Symbol] name repository to act on, :default is the default
19
+ #
20
+ # @api public
21
+ def auto_migrate!(repository_name = nil)
22
+ repository_execute(:auto_migrate!, repository_name)
23
+ end
24
+
25
+ # @api public
26
+ def auto_upgrade!(repository_name = nil)
27
+ repository_execute(:auto_upgrade!, repository_name)
28
+ end
29
+
30
+ private
31
+
32
+ # @api semipublic
33
+ def auto_migrate_down!(repository_name)
34
+ repository_execute(:auto_migrate_down!, repository_name)
35
+ end
36
+
37
+ # @api semipublic
38
+ def auto_migrate_up!(repository_name)
39
+ repository_execute(:auto_migrate_up!, repository_name)
40
+ end
41
+
42
+ # @api private
43
+ def repository_execute(method, repository_name)
44
+ DataMapper::Model.descendants.each do |model|
45
+ model.send(method, repository_name || model.default_repository_name)
46
+ end
47
+ end
48
+ end
49
+
50
+ module Repository
51
+ # Determine whether a particular named storage exists in this repository
52
+ #
53
+ # @param [String]
54
+ # storage_name name of the storage to test for
55
+ #
56
+ # @return [Boolean]
57
+ # true if the data-store +storage_name+ exists
58
+ #
59
+ # @api semipublic
60
+ def storage_exists?(storage_name)
61
+ adapter = self.adapter
62
+ if adapter.respond_to?(:storage_exists?)
63
+ adapter.storage_exists?(storage_name)
64
+ end
65
+ end
66
+
67
+ # @api semipublic
68
+ def upgrade_model_storage(model)
69
+ adapter = self.adapter
70
+ if adapter.respond_to?(:upgrade_model_storage)
71
+ adapter.upgrade_model_storage(model)
72
+ end
73
+ end
74
+
75
+ # @api semipublic
76
+ def create_model_storage(model)
77
+ adapter = self.adapter
78
+ if adapter.respond_to?(:create_model_storage)
79
+ adapter.create_model_storage(model)
80
+ end
81
+ end
82
+
83
+ # @api semipublic
84
+ def destroy_model_storage(model)
85
+ adapter = self.adapter
86
+ if adapter.respond_to?(:destroy_model_storage)
87
+ adapter.destroy_model_storage(model)
88
+ end
89
+ end
90
+
91
+ # Destructively automigrates the data-store to match the model.
92
+ # First migrates all models down and then up.
93
+ # REPEAT: THIS IS DESTRUCTIVE
94
+ #
95
+ # @api public
96
+ def auto_migrate!
97
+ DataMapper.auto_migrate!(name)
98
+ end
99
+
100
+ # Safely migrates the data-store to match the model
101
+ # preserving data already in the data-store
102
+ #
103
+ # @api public
104
+ def auto_upgrade!
105
+ DataMapper.auto_upgrade!(name)
106
+ end
107
+ end # module Repository
108
+
109
+ module Model
110
+
111
+ # @api private
112
+ def self.included(mod)
113
+ mod.descendants.each { |model| model.extend self }
114
+ end
115
+
116
+ # @api semipublic
117
+ def storage_exists?(repository_name = default_repository_name)
118
+ repository(repository_name).storage_exists?(storage_name(repository_name))
119
+ end
120
+
121
+ # Destructively automigrates the data-store to match the model
122
+ # REPEAT: THIS IS DESTRUCTIVE
123
+ #
124
+ # @param Symbol repository_name the repository to be migrated
125
+ #
126
+ # @api public
127
+ def auto_migrate!(repository_name = self.repository_name)
128
+ assert_valid(true)
129
+ auto_migrate_down!(repository_name)
130
+ auto_migrate_up!(repository_name)
131
+ end
132
+
133
+ # Safely migrates the data-store to match the model
134
+ # preserving data already in the data-store
135
+ #
136
+ # @param Symbol repository_name the repository to be migrated
137
+ #
138
+ # @api public
139
+ def auto_upgrade!(repository_name = self.repository_name)
140
+ assert_valid(true)
141
+ base_model = self.base_model
142
+ if base_model == self
143
+ repository(repository_name).upgrade_model_storage(self)
144
+ else
145
+ base_model.auto_upgrade!(repository_name)
146
+ end
147
+ end
148
+
149
+ # Destructively migrates the data-store down, which basically
150
+ # deletes all the models.
151
+ # REPEAT: THIS IS DESTRUCTIVE
152
+ #
153
+ # @param Symbol repository_name the repository to be migrated
154
+ #
155
+ # @api private
156
+ def auto_migrate_down!(repository_name = self.repository_name)
157
+ assert_valid(true)
158
+ base_model = self.base_model
159
+ if base_model == self
160
+ repository(repository_name).destroy_model_storage(self)
161
+ else
162
+ base_model.auto_migrate_down!(repository_name)
163
+ end
164
+ end
165
+
166
+ # Auto migrates the data-store to match the model
167
+ #
168
+ # @param Symbol repository_name the repository to be migrated
169
+ #
170
+ # @api private
171
+ def auto_migrate_up!(repository_name = self.repository_name)
172
+ assert_valid(true)
173
+ base_model = self.base_model
174
+ if base_model == self
175
+ repository(repository_name).create_model_storage(self)
176
+ else
177
+ base_model.auto_migrate_up!(repository_name)
178
+ end
179
+ end
180
+
181
+ end # module Model
182
+
183
+ def self.include_migration_api
184
+ DataMapper.extend(Migrations::SingletonMethods)
185
+ DataMapper::Model.send(:include, Migrations::Model)
186
+ DataMapper::Repository.send(:include, Migrations::Repository)
187
+ DataMapper::Model.append_extensions(Migrations::Model)
188
+ DataMapper::Repository.adapters.values.each do |adapter|
189
+ Adapters.include_migration_api(ActiveSupport::Inflector.demodulize(adapter.class.name))
190
+ end
191
+ end
192
+
193
+ end
194
+
195
+ module Adapters
196
+
197
+ extend Chainable
198
+
199
+ class << self
200
+
201
+ def include_migration_api(const_name)
202
+ require auto_migration_extensions(const_name)
203
+ adapter = const_get(const_name)
204
+ if DataMapper::Migrations.const_defined?(const_name)
205
+ adapter.send(:include, migration_module(const_name))
206
+ end
207
+ rescue LoadError
208
+ # do nothing
209
+ end
210
+
211
+ def migration_module(const_name)
212
+ DataMapper::Migrations.const_get(const_name)
213
+ end
214
+
215
+ private
216
+
217
+ # @api private
218
+ def auto_migration_extensions(const_name)
219
+ name = adapter_name(const_name)
220
+ name = 'do' if name == 'dataobjects'
221
+ "dm-migrations/adapters/dm-#{name}-adapter"
222
+ end
223
+
224
+ end
225
+
226
+ extendable do
227
+ # @api private
228
+ def const_added(const_name)
229
+ include_migration_api(const_name)
230
+ super
231
+ end
232
+ end
233
+
234
+ end # module Adapters
235
+
236
+ Migrations.include_migration_api
237
+
238
+ end # module DataMapper
@@ -22,9 +22,9 @@ module DataMapper
22
22
  @adapter = @database.adapter
23
23
 
24
24
  case @adapter.class.to_s
25
- when /Sqlite3/ then @adapter.extend(SQL::Sqlite3)
25
+ when /Sqlite/ then @adapter.extend(SQL::Sqlite)
26
26
  when /Mysql/ then @adapter.extend(SQL::Mysql)
27
- when /Postgres/ then @adapter.extend(SQL::Postgresql)
27
+ when /Postgres/ then @adapter.extend(SQL::Postgres)
28
28
  else
29
29
  raise "Unsupported Migration Adapter #{@adapter.class}"
30
30
  end
@@ -115,7 +115,7 @@ module DataMapper
115
115
  end
116
116
 
117
117
  # Orders migrations by position, so we know what order to run them in.
118
- # First order by postition, then by name, so at least the order is predictable.
118
+ # First order by position, then by name, so at least the order is predictable.
119
119
  def <=> other
120
120
  if self.position == other.position
121
121
  self.name.to_s <=> other.name.to_s
@@ -1,5 +1,5 @@
1
1
  require 'dm-migrations/sql/table_creator'
2
2
  require 'dm-migrations/sql/table_modifier'
3
- require 'dm-migrations/sql/sqlite3'
3
+ require 'dm-migrations/sql/sqlite'
4
4
  require 'dm-migrations/sql/mysql'
5
- require 'dm-migrations/sql/postgresql'
5
+ require 'dm-migrations/sql/postgres'
@@ -12,9 +12,9 @@ module SQL
12
12
  end
13
13
 
14
14
  def recreate_database
15
- execute "DROP DATABASE #{db_name}"
16
- execute "CREATE DATABASE #{db_name}"
17
- execute "USE #{db_name}"
15
+ execute "DROP DATABASE #{schema_name}"
16
+ execute "CREATE DATABASE #{schema_name}"
17
+ execute "USE #{schema_name}"
18
18
  end
19
19
 
20
20
  def supports_serial?
@@ -1,12 +1,12 @@
1
1
  module SQL
2
- module Postgresql
2
+ module Postgres
3
3
 
4
4
  def supports_schema_transactions?
5
5
  true
6
6
  end
7
7
 
8
8
  def table(table_name)
9
- SQL::Postgresql::Table.new(self, table_name)
9
+ SQL::Postgres::Table.new(self, table_name)
10
10
  end
11
11
 
12
12
  def recreate_database
@@ -41,7 +41,7 @@ module SQL
41
41
  @adapter, @name = adapter, table_name
42
42
  @columns = []
43
43
  adapter.query_table(table_name).each do |col_struct|
44
- @columns << SQL::Postgresql::Column.new(col_struct)
44
+ @columns << SQL::Postgres::Column.new(col_struct)
45
45
  end
46
46
 
47
47
  query_column_constraints
@@ -1,14 +1,14 @@
1
1
  require 'dm-migrations/sql/table'
2
2
 
3
3
  module SQL
4
- module Sqlite3
4
+ module Sqlite
5
5
 
6
6
  def supports_schema_transactions?
7
7
  true
8
8
  end
9
9
 
10
10
  def table(table_name)
11
- SQL::Sqlite3::Table.new(self, table_name)
11
+ SQL::Sqlite::Table.new(self, table_name)
12
12
  end
13
13
 
14
14
  def recreate_database
@@ -29,7 +29,7 @@ module SQL
29
29
  def initialize(adapter, table_name)
30
30
  @columns = []
31
31
  adapter.table_info(table_name).each do |col_struct|
32
- @columns << SQL::Sqlite3::Column.new(col_struct)
32
+ @columns << SQL::Sqlite::Column.new(col_struct)
33
33
  end
34
34
  end
35
35
  end
@@ -0,0 +1,506 @@
1
+ require 'spec_helper'
2
+
3
+ require 'dm-migrations/auto_migration'
4
+
5
+ describe DataMapper::Migrations do
6
+ def capture_log(mod)
7
+ original, mod.logger = mod.logger, DataObjects::Logger.new(@log = StringIO.new, :debug)
8
+ yield
9
+ ensure
10
+ @log.rewind
11
+ @output = @log.readlines.map do |line|
12
+ line.chomp.gsub(/\A.+?~ \(\d+\.?\d*\)\s+/, '')
13
+ end
14
+
15
+ mod.logger = original
16
+ end
17
+
18
+ supported_by :mysql do
19
+ before :all do
20
+ module ::Blog
21
+ class Article
22
+ include DataMapper::Resource
23
+ end
24
+ end
25
+
26
+ @model = ::Blog::Article
27
+ end
28
+
29
+ describe '#auto_migrate' do
30
+ describe 'Integer property' do
31
+ [
32
+ [ 0, 1, 'TINYINT(1) UNSIGNED' ],
33
+ [ 0, 9, 'TINYINT(1) UNSIGNED' ],
34
+ [ 0, 10, 'TINYINT(2) UNSIGNED' ],
35
+ [ 0, 99, 'TINYINT(2) UNSIGNED' ],
36
+ [ 0, 100, 'TINYINT(3) UNSIGNED' ],
37
+ [ 0, 255, 'TINYINT(3) UNSIGNED' ],
38
+ [ 0, 256, 'SMALLINT(3) UNSIGNED' ],
39
+ [ 0, 999, 'SMALLINT(3) UNSIGNED' ],
40
+ [ 0, 1000, 'SMALLINT(4) UNSIGNED' ],
41
+ [ 0, 9999, 'SMALLINT(4) UNSIGNED' ],
42
+ [ 0, 10000, 'SMALLINT(5) UNSIGNED' ],
43
+ [ 0, 65535, 'SMALLINT(5) UNSIGNED' ],
44
+ [ 0, 65536, 'MEDIUMINT(5) UNSIGNED' ],
45
+ [ 0, 99999, 'MEDIUMINT(5) UNSIGNED' ],
46
+ [ 0, 100000, 'MEDIUMINT(6) UNSIGNED' ],
47
+ [ 0, 999999, 'MEDIUMINT(6) UNSIGNED' ],
48
+ [ 0, 1000000, 'MEDIUMINT(7) UNSIGNED' ],
49
+ [ 0, 9999999, 'MEDIUMINT(7) UNSIGNED' ],
50
+ [ 0, 10000000, 'MEDIUMINT(8) UNSIGNED' ],
51
+ [ 0, 16777215, 'MEDIUMINT(8) UNSIGNED' ],
52
+ [ 0, 16777216, 'INT(8) UNSIGNED' ],
53
+ [ 0, 99999999, 'INT(8) UNSIGNED' ],
54
+ [ 0, 100000000, 'INT(9) UNSIGNED' ],
55
+ [ 0, 999999999, 'INT(9) UNSIGNED' ],
56
+ [ 0, 1000000000, 'INT(10) UNSIGNED' ],
57
+ [ 0, 4294967295, 'INT(10) UNSIGNED' ],
58
+ [ 0, 4294967296, 'BIGINT(10) UNSIGNED' ],
59
+ [ 0, 9999999999, 'BIGINT(10) UNSIGNED' ],
60
+ [ 0, 10000000000, 'BIGINT(11) UNSIGNED' ],
61
+ [ 0, 99999999999, 'BIGINT(11) UNSIGNED' ],
62
+ [ 0, 100000000000, 'BIGINT(12) UNSIGNED' ],
63
+ [ 0, 999999999999, 'BIGINT(12) UNSIGNED' ],
64
+ [ 0, 1000000000000, 'BIGINT(13) UNSIGNED' ],
65
+ [ 0, 9999999999999, 'BIGINT(13) UNSIGNED' ],
66
+ [ 0, 10000000000000, 'BIGINT(14) UNSIGNED' ],
67
+ [ 0, 99999999999999, 'BIGINT(14) UNSIGNED' ],
68
+ [ 0, 100000000000000, 'BIGINT(15) UNSIGNED' ],
69
+ [ 0, 999999999999999, 'BIGINT(15) UNSIGNED' ],
70
+ [ 0, 1000000000000000, 'BIGINT(16) UNSIGNED' ],
71
+ [ 0, 9999999999999999, 'BIGINT(16) UNSIGNED' ],
72
+ [ 0, 10000000000000000, 'BIGINT(17) UNSIGNED' ],
73
+ [ 0, 99999999999999999, 'BIGINT(17) UNSIGNED' ],
74
+ [ 0, 100000000000000000, 'BIGINT(18) UNSIGNED' ],
75
+ [ 0, 999999999999999999, 'BIGINT(18) UNSIGNED' ],
76
+ [ 0, 1000000000000000000, 'BIGINT(19) UNSIGNED' ],
77
+ [ 0, 9999999999999999999, 'BIGINT(19) UNSIGNED' ],
78
+ [ 0, 10000000000000000000, 'BIGINT(20) UNSIGNED' ],
79
+ [ 0, 18446744073709551615, 'BIGINT(20) UNSIGNED' ],
80
+
81
+ [ -1, 0, 'TINYINT(2)' ],
82
+ [ -1, 9, 'TINYINT(2)' ],
83
+ [ -1, 10, 'TINYINT(2)' ],
84
+ [ -1, 99, 'TINYINT(2)' ],
85
+ [ -1, 100, 'TINYINT(3)' ],
86
+ [ -1, 127, 'TINYINT(3)' ],
87
+ [ -1, 128, 'SMALLINT(3)' ],
88
+ [ -1, 999, 'SMALLINT(3)' ],
89
+ [ -1, 1000, 'SMALLINT(4)' ],
90
+ [ -1, 9999, 'SMALLINT(4)' ],
91
+ [ -1, 10000, 'SMALLINT(5)' ],
92
+ [ -1, 32767, 'SMALLINT(5)' ],
93
+ [ -1, 32768, 'MEDIUMINT(5)' ],
94
+ [ -1, 99999, 'MEDIUMINT(5)' ],
95
+ [ -1, 100000, 'MEDIUMINT(6)' ],
96
+ [ -1, 999999, 'MEDIUMINT(6)' ],
97
+ [ -1, 1000000, 'MEDIUMINT(7)' ],
98
+ [ -1, 8388607, 'MEDIUMINT(7)' ],
99
+ [ -1, 8388608, 'INT(7)' ],
100
+ [ -1, 9999999, 'INT(7)' ],
101
+ [ -1, 10000000, 'INT(8)' ],
102
+ [ -1, 99999999, 'INT(8)' ],
103
+ [ -1, 100000000, 'INT(9)' ],
104
+ [ -1, 999999999, 'INT(9)' ],
105
+ [ -1, 1000000000, 'INT(10)' ],
106
+ [ -1, 2147483647, 'INT(10)' ],
107
+ [ -1, 2147483648, 'BIGINT(10)' ],
108
+ [ -1, 9999999999, 'BIGINT(10)' ],
109
+ [ -1, 10000000000, 'BIGINT(11)' ],
110
+ [ -1, 99999999999, 'BIGINT(11)' ],
111
+ [ -1, 100000000000, 'BIGINT(12)' ],
112
+ [ -1, 999999999999, 'BIGINT(12)' ],
113
+ [ -1, 1000000000000, 'BIGINT(13)' ],
114
+ [ -1, 9999999999999, 'BIGINT(13)' ],
115
+ [ -1, 10000000000000, 'BIGINT(14)' ],
116
+ [ -1, 99999999999999, 'BIGINT(14)' ],
117
+ [ -1, 100000000000000, 'BIGINT(15)' ],
118
+ [ -1, 999999999999999, 'BIGINT(15)' ],
119
+ [ -1, 1000000000000000, 'BIGINT(16)' ],
120
+ [ -1, 9999999999999999, 'BIGINT(16)' ],
121
+ [ -1, 10000000000000000, 'BIGINT(17)' ],
122
+ [ -1, 99999999999999999, 'BIGINT(17)' ],
123
+ [ -1, 100000000000000000, 'BIGINT(18)' ],
124
+ [ -1, 999999999999999999, 'BIGINT(18)' ],
125
+ [ -1, 1000000000000000000, 'BIGINT(19)' ],
126
+ [ -1, 9223372036854775807, 'BIGINT(19)' ],
127
+
128
+ [ -1, 0, 'TINYINT(2)' ],
129
+ [ -9, 0, 'TINYINT(2)' ],
130
+ [ -10, 0, 'TINYINT(3)' ],
131
+ [ -99, 0, 'TINYINT(3)' ],
132
+ [ -100, 0, 'TINYINT(4)' ],
133
+ [ -128, 0, 'TINYINT(4)' ],
134
+ [ -129, 0, 'SMALLINT(4)' ],
135
+ [ -999, 0, 'SMALLINT(4)' ],
136
+ [ -1000, 0, 'SMALLINT(5)' ],
137
+ [ -9999, 0, 'SMALLINT(5)' ],
138
+ [ -10000, 0, 'SMALLINT(6)' ],
139
+ [ -32768, 0, 'SMALLINT(6)' ],
140
+ [ -32769, 0, 'MEDIUMINT(6)' ],
141
+ [ -99999, 0, 'MEDIUMINT(6)' ],
142
+ [ -100000, 0, 'MEDIUMINT(7)' ],
143
+ [ -999999, 0, 'MEDIUMINT(7)' ],
144
+ [ -1000000, 0, 'MEDIUMINT(8)' ],
145
+ [ -8388608, 0, 'MEDIUMINT(8)' ],
146
+ [ -8388609, 0, 'INT(8)' ],
147
+ [ -9999999, 0, 'INT(8)' ],
148
+ [ -10000000, 0, 'INT(9)' ],
149
+ [ -99999999, 0, 'INT(9)' ],
150
+ [ -100000000, 0, 'INT(10)' ],
151
+ [ -999999999, 0, 'INT(10)' ],
152
+ [ -1000000000, 0, 'INT(11)' ],
153
+ [ -2147483648, 0, 'INT(11)' ],
154
+ [ -2147483649, 0, 'BIGINT(11)' ],
155
+ [ -9999999999, 0, 'BIGINT(11)' ],
156
+ [ -10000000000, 0, 'BIGINT(12)' ],
157
+ [ -99999999999, 0, 'BIGINT(12)' ],
158
+ [ -100000000000, 0, 'BIGINT(13)' ],
159
+ [ -999999999999, 0, 'BIGINT(13)' ],
160
+ [ -1000000000000, 0, 'BIGINT(14)' ],
161
+ [ -9999999999999, 0, 'BIGINT(14)' ],
162
+ [ -10000000000000, 0, 'BIGINT(15)' ],
163
+ [ -99999999999999, 0, 'BIGINT(15)' ],
164
+ [ -100000000000000, 0, 'BIGINT(16)' ],
165
+ [ -999999999999999, 0, 'BIGINT(16)' ],
166
+ [ -1000000000000000, 0, 'BIGINT(17)' ],
167
+ [ -9999999999999999, 0, 'BIGINT(17)' ],
168
+ [ -10000000000000000, 0, 'BIGINT(18)' ],
169
+ [ -99999999999999999, 0, 'BIGINT(18)' ],
170
+ [ -100000000000000000, 0, 'BIGINT(19)' ],
171
+ [ -999999999999999999, 0, 'BIGINT(19)' ],
172
+ [ -1000000000000000000, 0, 'BIGINT(20)' ],
173
+ [ -9223372036854775808, 0, 'BIGINT(20)' ],
174
+
175
+ [ nil, 2147483647, 'INT(10) UNSIGNED' ],
176
+ [ 0, nil, 'INT(10) UNSIGNED' ],
177
+ [ nil, nil, 'INTEGER' ],
178
+ ].each do |min, max, statement|
179
+ options = { :key => true }
180
+ options[:min] = min if min
181
+ options[:max] = max if max
182
+
183
+ describe "with a min of #{min} and a max of #{max}" do
184
+ before :all do
185
+ @property = @model.property(:id, Integer, options)
186
+
187
+ @response = capture_log(DataObjects::Mysql) { @model.auto_migrate! }
188
+ end
189
+
190
+ it 'should return true' do
191
+ @response.should be_true
192
+ end
193
+
194
+ it "should create a #{statement} column" do
195
+ @output.last.should =~ %r{\ACREATE TABLE `blog_articles` \(`id` #{Regexp.escape(statement)} NOT NULL, PRIMARY KEY\(`id`\)\) ENGINE = InnoDB CHARACTER SET [a-z\d]+ COLLATE (?:[a-z\d](?:_?[a-z\d]+)*)\z}
196
+ end
197
+
198
+ options.only(:min, :max).each do |key, value|
199
+ it "should allow the #{key} value #{value} to be stored" do
200
+ lambda {
201
+ resource = @model.create(@property => value)
202
+ @model.first(@property => value).should eql(resource)
203
+ }.should_not raise_error
204
+ end
205
+ end
206
+ end
207
+ end
208
+ end
209
+
210
+ describe 'Text property' do
211
+ before :all do
212
+ @model.property(:id, DataMapper::Property::Serial)
213
+ end
214
+
215
+ [
216
+ [ 0, 'TINYTEXT' ],
217
+ [ 1, 'TINYTEXT' ],
218
+ [ 255, 'TINYTEXT' ],
219
+ [ 256, 'TEXT' ],
220
+ [ 65535, 'TEXT' ],
221
+ [ 65536, 'MEDIUMTEXT' ],
222
+ [ 16777215, 'MEDIUMTEXT' ],
223
+ [ 16777216, 'LONGTEXT' ],
224
+ [ 4294967295, 'LONGTEXT' ],
225
+
226
+ [ nil, 'TEXT' ],
227
+ ].each do |length, statement|
228
+ options = {}
229
+ options[:length] = length if length
230
+
231
+ describe "with a length of #{length}" do
232
+ before :all do
233
+ @property = @model.property(:body, DataMapper::Types::Text, options)
234
+
235
+ @response = capture_log(DataObjects::Mysql) { @model.auto_migrate! }
236
+ end
237
+
238
+ it 'should return true' do
239
+ @response.should be_true
240
+ end
241
+
242
+ it "should create a #{statement} column" do
243
+ @output.last.should =~ %r{\ACREATE TABLE `blog_articles` \(`id` INT\(10\) UNSIGNED NOT NULL AUTO_INCREMENT, `body` #{Regexp.escape(statement)}, PRIMARY KEY\(`id`\)\) ENGINE = InnoDB CHARACTER SET [a-z\d]+ COLLATE (?:[a-z\d](?:_?[a-z\d]+)*)\z}
244
+ end
245
+ end
246
+ end
247
+ end
248
+
249
+ describe 'String property' do
250
+ before :all do
251
+ @model.property(:id, DataMapper::Property::Serial)
252
+ end
253
+
254
+ [
255
+ [ 1, 'VARCHAR(1)' ],
256
+ [ 50, 'VARCHAR(50)' ],
257
+ [ 255, 'VARCHAR(255)' ],
258
+ [ nil, 'VARCHAR(50)' ],
259
+ ].each do |length, statement|
260
+ options = {}
261
+ options[:length] = length if length
262
+
263
+ describe "with a length of #{length}" do
264
+ before :all do
265
+ @property = @model.property(:title, String, options)
266
+
267
+ @response = capture_log(DataObjects::Mysql) { @model.auto_migrate! }
268
+ end
269
+
270
+ it 'should return true' do
271
+ @response.should be_true
272
+ end
273
+
274
+ it "should create a #{statement} column" do
275
+ @output.last.should =~ %r{\ACREATE TABLE `blog_articles` \(`id` INT\(10\) UNSIGNED NOT NULL AUTO_INCREMENT, `title` #{Regexp.escape(statement)}, PRIMARY KEY\(`id`\)\) ENGINE = InnoDB CHARACTER SET [a-z\d]+ COLLATE (?:[a-z\d](?:_?[a-z\d]+)*)\z}
276
+ end
277
+ end
278
+ end
279
+ end
280
+ end
281
+ end
282
+
283
+ supported_by :postgres do
284
+ before :all do
285
+ module ::Blog
286
+ class Article
287
+ include DataMapper::Resource
288
+ end
289
+ end
290
+
291
+ @model = ::Blog::Article
292
+ end
293
+
294
+ describe '#auto_migrate' do
295
+ describe 'Integer property' do
296
+ [
297
+ [ 0, 1, 'SMALLINT' ],
298
+ [ 0, 32767, 'SMALLINT' ],
299
+ [ 0, 32768, 'INTEGER' ],
300
+ [ 0, 2147483647, 'INTEGER' ],
301
+ [ 0, 2147483648, 'BIGINT' ],
302
+ [ 0, 9223372036854775807, 'BIGINT' ],
303
+
304
+ [ -1, 1, 'SMALLINT' ],
305
+ [ -1, 32767, 'SMALLINT' ],
306
+ [ -1, 32768, 'INTEGER' ],
307
+ [ -1, 2147483647, 'INTEGER' ],
308
+ [ -1, 2147483648, 'BIGINT' ],
309
+ [ -1, 9223372036854775807, 'BIGINT' ],
310
+
311
+ [ -1, 0, 'SMALLINT' ],
312
+ [ -32768, 0, 'SMALLINT' ],
313
+ [ -32769, 0, 'INTEGER' ],
314
+ [ -2147483648, 0, 'INTEGER' ],
315
+ [ -2147483649, 0, 'BIGINT' ],
316
+ [ -9223372036854775808, 0, 'BIGINT' ],
317
+
318
+ [ nil, 2147483647, 'INTEGER' ],
319
+ [ 0, nil, 'INTEGER' ],
320
+ [ nil, nil, 'INTEGER' ],
321
+ ].each do |min, max, statement|
322
+ options = { :key => true }
323
+ options[:min] = min if min
324
+ options[:max] = max if max
325
+
326
+ describe "with a min of #{min} and a max of #{max}" do
327
+ before :all do
328
+ @property = @model.property(:id, Integer, options)
329
+
330
+ @response = capture_log(DataObjects::Postgres) { @model.auto_migrate! }
331
+ end
332
+
333
+ it 'should return true' do
334
+ @response.should be_true
335
+ end
336
+
337
+ it "should create a #{statement} column" do
338
+ @output[-2].should == "CREATE TABLE \"blog_articles\" (\"id\" #{statement} NOT NULL, PRIMARY KEY(\"id\"))"
339
+ end
340
+
341
+ options.only(:min, :max).each do |key, value|
342
+ it "should allow the #{key} value #{value} to be stored" do
343
+ lambda {
344
+ resource = @model.create(@property => value)
345
+ @model.first(@property => value).should eql(resource)
346
+ }.should_not raise_error
347
+ end
348
+ end
349
+ end
350
+ end
351
+ end
352
+
353
+ describe 'Serial property' do
354
+ [
355
+ [ 1, 'SERIAL' ],
356
+ [ 2147483647, 'SERIAL' ],
357
+ [ 2147483648, 'BIGSERIAL' ],
358
+ [ 9223372036854775807, 'BIGSERIAL' ],
359
+
360
+ [ nil, 'SERIAL' ],
361
+ ].each do |max, statement|
362
+ options = {}
363
+ options[:max] = max if max
364
+
365
+ describe "with a max of #{max}" do
366
+ before :all do
367
+ @property = @model.property(:id, DataMapper::Property::Serial, options)
368
+
369
+ @response = capture_log(DataObjects::Postgres) { @model.auto_migrate! }
370
+ end
371
+
372
+ it 'should return true' do
373
+ @response.should be_true
374
+ end
375
+
376
+ it "should create a #{statement} column" do
377
+ @output[-2].should == "CREATE TABLE \"blog_articles\" (\"id\" #{statement} NOT NULL, PRIMARY KEY(\"id\"))"
378
+ end
379
+
380
+ options.only(:min, :max).each do |key, value|
381
+ it "should allow the #{key} value #{value} to be stored" do
382
+ lambda {
383
+ resource = @model.create(@property => value)
384
+ @model.first(@property => value).should eql(resource)
385
+ }.should_not raise_error
386
+ end
387
+ end
388
+ end
389
+ end
390
+ end
391
+
392
+ describe 'String property' do
393
+ before :all do
394
+ @model.property(:id, DataMapper::Property::Serial)
395
+ end
396
+
397
+ [
398
+ [ 1, 'VARCHAR(1)' ],
399
+ [ 50, 'VARCHAR(50)' ],
400
+ [ 255, 'VARCHAR(255)' ],
401
+ [ nil, 'VARCHAR(50)' ],
402
+ ].each do |length, statement|
403
+ options = {}
404
+ options[:length] = length if length
405
+
406
+ describe "with a length of #{length}" do
407
+ before :all do
408
+ @property = @model.property(:title, String, options)
409
+
410
+ @response = capture_log(DataObjects::Postgres) { @model.auto_migrate! }
411
+ end
412
+
413
+ it 'should return true' do
414
+ @response.should be_true
415
+ end
416
+
417
+ it "should create a #{statement} column" do
418
+ @output[-2].should == "CREATE TABLE \"blog_articles\" (\"id\" SERIAL NOT NULL, \"title\" #{statement}, PRIMARY KEY(\"id\"))"
419
+ end
420
+ end
421
+ end
422
+ end
423
+ end
424
+ end
425
+
426
+ supported_by :sqlserver do
427
+ before :all do
428
+ module ::Blog
429
+ class Article
430
+ include DataMapper::Resource
431
+ end
432
+ end
433
+
434
+ @model = ::Blog::Article
435
+ end
436
+
437
+ describe '#auto_migrate' do
438
+ describe 'Integer property' do
439
+ [
440
+ [ 0, 1, 'TINYINT' ],
441
+ [ 0, 255, 'TINYINT' ],
442
+ [ 0, 256, 'SMALLINT' ],
443
+ [ 0, 32767, 'SMALLINT' ],
444
+ [ 0, 32768, 'INT' ],
445
+ [ 0, 2147483647, 'INT' ],
446
+ [ 0, 2147483648, 'BIGINT' ],
447
+ [ 0, 9223372036854775807, 'BIGINT' ],
448
+
449
+ [ -1, 1, 'SMALLINT' ],
450
+ [ -1, 255, 'SMALLINT' ],
451
+ [ -1, 256, 'SMALLINT' ],
452
+ [ -1, 32767, 'SMALLINT' ],
453
+ [ -1, 32768, 'INT' ],
454
+ [ -1, 2147483647, 'INT' ],
455
+ [ -1, 2147483648, 'BIGINT' ],
456
+ [ -1, 9223372036854775807, 'BIGINT' ],
457
+
458
+ [ -1, 0, 'SMALLINT' ],
459
+ [ -32768, 0, 'SMALLINT' ],
460
+ [ -32769, 0, 'INT' ],
461
+ [ -2147483648, 0, 'INT' ],
462
+ [ -2147483649, 0, 'BIGINT' ],
463
+ [ -9223372036854775808, 0, 'BIGINT' ],
464
+
465
+ [ nil, 2147483647, 'INT' ],
466
+ [ 0, nil, 'INT' ],
467
+ [ nil, nil, 'INTEGER' ],
468
+ ].each do |min, max, statement|
469
+ options = { :key => true }
470
+ options[:min] = min if min
471
+ options[:max] = max if max
472
+
473
+ describe "with a min of #{min} and a max of #{max}" do
474
+ before :all do
475
+ @property = @model.property(:id, Integer, options)
476
+
477
+ @response = capture_log(DataObjects::Sqlserver) { @model.auto_migrate! }
478
+ end
479
+
480
+ it 'should return true' do
481
+ @response.should be_true
482
+ end
483
+
484
+ it "should create a #{statement} column" do
485
+ @output.last.should == "CREATE TABLE \"blog_articles\" (\"id\" #{statement} NOT NULL, PRIMARY KEY(\"id\"))"
486
+ end
487
+
488
+ options.only(:min, :max).each do |key, value|
489
+ it "should allow the #{key} value #{value} to be stored" do
490
+ lambda {
491
+ resource = @model.create(@property => value)
492
+ @model.first(@property => value).should eql(resource)
493
+ }.should_not raise_error
494
+ end
495
+ end
496
+ end
497
+ end
498
+ end
499
+
500
+ describe 'String property' do
501
+ it 'needs specs'
502
+ end
503
+ end
504
+ end
505
+
506
+ end