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.
- data/.gitignore +36 -0
- data/Gemfile +141 -0
- data/Rakefile +2 -3
- data/VERSION +1 -1
- data/dm-migrations.gemspec +50 -18
- data/lib/dm-migrations.rb +2 -0
- data/lib/dm-migrations/adapters/dm-do-adapter.rb +276 -0
- data/lib/dm-migrations/adapters/dm-mysql-adapter.rb +283 -0
- data/lib/dm-migrations/adapters/dm-oracle-adapter.rb +321 -0
- data/lib/dm-migrations/adapters/dm-postgres-adapter.rb +159 -0
- data/lib/dm-migrations/adapters/dm-sqlite-adapter.rb +96 -0
- data/lib/dm-migrations/adapters/dm-sqlserver-adapter.rb +177 -0
- data/lib/dm-migrations/adapters/dm-yaml-adapter.rb +23 -0
- data/lib/dm-migrations/auto_migration.rb +238 -0
- data/lib/dm-migrations/migration.rb +3 -3
- data/lib/dm-migrations/sql.rb +2 -2
- data/lib/dm-migrations/sql/mysql.rb +3 -3
- data/lib/dm-migrations/sql/{postgresql.rb → postgres.rb} +3 -3
- data/lib/dm-migrations/sql/{sqlite3.rb → sqlite.rb} +3 -3
- data/spec/integration/auto_migration_spec.rb +506 -0
- data/spec/integration/migration_runner_spec.rb +12 -2
- data/spec/integration/migration_spec.rb +28 -14
- data/spec/integration/sql_spec.rb +22 -21
- data/spec/isolated/require_after_setup_spec.rb +30 -0
- data/spec/isolated/require_before_setup_spec.rb +30 -0
- data/spec/isolated/require_spec.rb +25 -0
- data/spec/spec_helper.rb +10 -25
- data/spec/unit/migration_spec.rb +320 -319
- data/spec/unit/sql/{postgresql_spec.rb → postgres_spec.rb} +17 -17
- data/spec/unit/sql/{sqlite3_extensions_spec.rb → sqlite_extensions_spec.rb} +14 -14
- data/tasks/local_gemfile.rake +18 -0
- data/tasks/spec.rake +0 -3
- 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 /
|
25
|
+
when /Sqlite/ then @adapter.extend(SQL::Sqlite)
|
26
26
|
when /Mysql/ then @adapter.extend(SQL::Mysql)
|
27
|
-
when /Postgres/ then @adapter.extend(SQL::
|
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
|
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
|
data/lib/dm-migrations/sql.rb
CHANGED
@@ -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/
|
3
|
+
require 'dm-migrations/sql/sqlite'
|
4
4
|
require 'dm-migrations/sql/mysql'
|
5
|
-
require 'dm-migrations/sql/
|
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 #{
|
16
|
-
execute "CREATE DATABASE #{
|
17
|
-
execute "USE #{
|
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
|
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::
|
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::
|
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
|
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::
|
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::
|
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
|