dm-hibernate-migrations 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/lib/dm-migrations.rb +3 -0
  2. data/lib/dm-migrations/adapters/dm-do-adapter.rb +284 -0
  3. data/lib/dm-migrations/adapters/dm-mysql-adapter.rb +283 -0
  4. data/lib/dm-migrations/adapters/dm-oracle-adapter.rb +321 -0
  5. data/lib/dm-migrations/adapters/dm-postgres-adapter.rb +159 -0
  6. data/lib/dm-migrations/adapters/dm-sqlite-adapter.rb +96 -0
  7. data/lib/dm-migrations/adapters/dm-sqlserver-adapter.rb +177 -0
  8. data/lib/dm-migrations/adapters/dm-yaml-adapter.rb +23 -0
  9. data/lib/dm-migrations/auto_migration.rb +237 -0
  10. data/lib/dm-migrations/migration.rb +217 -0
  11. data/lib/dm-migrations/migration_runner.rb +85 -0
  12. data/lib/dm-migrations/sql.rb +5 -0
  13. data/lib/dm-migrations/sql/column.rb +5 -0
  14. data/lib/dm-migrations/sql/mysql.rb +53 -0
  15. data/lib/dm-migrations/sql/postgres.rb +78 -0
  16. data/lib/dm-migrations/sql/sqlite.rb +45 -0
  17. data/lib/dm-migrations/sql/table.rb +15 -0
  18. data/lib/dm-migrations/sql/table_creator.rb +102 -0
  19. data/lib/dm-migrations/sql/table_modifier.rb +51 -0
  20. data/lib/spec/example/migration_example_group.rb +73 -0
  21. data/lib/spec/matchers/migration_matchers.rb +106 -0
  22. data/spec/integration/auto_migration_spec.rb +506 -0
  23. data/spec/integration/migration_runner_spec.rb +89 -0
  24. data/spec/integration/migration_spec.rb +138 -0
  25. data/spec/integration/sql_spec.rb +190 -0
  26. data/spec/isolated/require_after_setup_spec.rb +30 -0
  27. data/spec/isolated/require_before_setup_spec.rb +30 -0
  28. data/spec/isolated/require_spec.rb +25 -0
  29. data/spec/rcov.opts +6 -0
  30. data/spec/spec.opts +4 -0
  31. data/spec/spec_helper.rb +16 -0
  32. data/spec/unit/migration_spec.rb +453 -0
  33. data/spec/unit/sql/column_spec.rb +14 -0
  34. data/spec/unit/sql/postgres_spec.rb +97 -0
  35. data/spec/unit/sql/sqlite_extensions_spec.rb +108 -0
  36. data/spec/unit/sql/table_creator_spec.rb +94 -0
  37. data/spec/unit/sql/table_modifier_spec.rb +49 -0
  38. data/spec/unit/sql/table_spec.rb +28 -0
  39. data/spec/unit/sql_spec.rb +7 -0
  40. metadata +157 -0
@@ -0,0 +1,45 @@
1
+ require 'dm-migrations/sql/table'
2
+
3
+ module SQL
4
+ module Sqlite
5
+
6
+ def supports_schema_transactions?
7
+ true
8
+ end
9
+
10
+ def table(table_name)
11
+ SQL::Sqlite::Table.new(self, table_name)
12
+ end
13
+
14
+ def recreate_database
15
+ DataMapper.logger.info "Dropping #{@uri.path}"
16
+ system "rm #{@uri.path}"
17
+ # do nothing, sqlite will automatically create the database file
18
+ end
19
+
20
+ def table_options
21
+ ''
22
+ end
23
+
24
+ def supports_serial?
25
+ true
26
+ end
27
+
28
+ class Table < SQL::Table
29
+ def initialize(adapter, table_name)
30
+ @columns = []
31
+ adapter.table_info(table_name).each do |col_struct|
32
+ @columns << SQL::Sqlite::Column.new(col_struct)
33
+ end
34
+ end
35
+ end
36
+
37
+ class Column < SQL::Column
38
+ def initialize(col_struct)
39
+ @name, @type, @default_value, @primary_key = col_struct.name, col_struct.type, col_struct.dflt_value, col_struct.pk
40
+
41
+ @not_null = col_struct.notnull == 0
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,15 @@
1
+ require 'dm-migrations/sql/column'
2
+
3
+ module SQL
4
+ class Table
5
+ attr_accessor :name, :columns
6
+
7
+ def to_s
8
+ name
9
+ end
10
+
11
+ def column(column_name)
12
+ @columns.select { |c| c.name == column_name.to_s }.first
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,102 @@
1
+ module SQL
2
+ class TableCreator
3
+ attr_accessor :table_name, :opts
4
+
5
+ def initialize(adapter, table_name, opts = {}, &block)
6
+ @adapter = adapter
7
+ @table_name = table_name.to_s
8
+ @opts = opts
9
+
10
+ @columns = []
11
+
12
+ self.instance_eval &block
13
+ end
14
+
15
+ def quoted_table_name
16
+ @adapter.send(:quote_name, table_name)
17
+ end
18
+
19
+ def column(name, type, opts = {})
20
+ @columns << Column.new(@adapter, name, type, opts)
21
+ end
22
+
23
+ def to_sql
24
+ "CREATE TABLE #{quoted_table_name} (#{@columns.map{ |c| c.to_sql }.join(', ')})#{@adapter.table_options}"
25
+ end
26
+
27
+ # A helper for using the native NOW() SQL function in a default
28
+ def now
29
+ SqlExpr.new('NOW()')
30
+ end
31
+
32
+ # A helper for using the native UUID() SQL function in a default
33
+ def uuid
34
+ SqlExpr.new('UUID()')
35
+ end
36
+
37
+ class SqlExpr
38
+ attr_accessor :sql
39
+ def initialize(sql)
40
+ @sql = sql
41
+ end
42
+
43
+ def to_s
44
+ @sql.to_s
45
+ end
46
+ end
47
+
48
+ class Column
49
+ attr_accessor :name, :type
50
+
51
+ def initialize(adapter, name, type, opts = {})
52
+ @adapter = adapter
53
+ @name = name.to_s
54
+ @opts = opts
55
+ @type = build_type(type)
56
+ end
57
+
58
+ def to_sql
59
+ type
60
+ end
61
+
62
+ private
63
+
64
+ def build_type(type_class)
65
+ schema = { :name => @name, :quote_column_name => quoted_name }.merge(@opts)
66
+
67
+ [ :nullable, :nullable? ].each do |option|
68
+ next if (value = schema.delete(option)).nil?
69
+ warn "#{option.inspect} is deprecated, use :allow_nil instead"
70
+ schema[:allow_nil] = value unless schema.key?(:allow_nil)
71
+ end
72
+
73
+ unless schema.key?(:allow_nil)
74
+ schema[:allow_nil] = !schema[:not_null]
75
+ end
76
+
77
+ schema[:length] ||= schema.delete(:size) if schema.key?(:size)
78
+
79
+ if type_class.kind_of?(String)
80
+ schema[:primitive] = type_class
81
+ else
82
+ primitive = type_class.respond_to?(:primitive) ? type_class.primitive : type_class
83
+ options = @adapter.class.type_map[primitive].dup
84
+
85
+ if type_class.respond_to?(:options) && type_class.options.kind_of?(options.class)
86
+ options.update(type_class.options)
87
+ end
88
+
89
+ schema = options.update(schema)
90
+ end
91
+
92
+ @adapter.send(:with_connection) do |connection|
93
+ @adapter.property_schema_statement(connection, schema)
94
+ end
95
+ end
96
+
97
+ def quoted_name
98
+ @adapter.send(:quote_name, name)
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,51 @@
1
+ module SQL
2
+ class TableModifier
3
+ attr_accessor :table_name, :opts, :statements, :adapter
4
+
5
+ def initialize(adapter, table_name, opts = {}, &block)
6
+ @adapter = adapter
7
+ @table_name = table_name.to_s
8
+ @opts = (opts)
9
+
10
+ @statements = []
11
+
12
+ self.instance_eval &block
13
+ end
14
+
15
+ def add_column(name, type, opts = {})
16
+ column = SQL::TableCreator::Column.new(@adapter, name, type, opts)
17
+ @statements << "ALTER TABLE #{quoted_table_name} ADD COLUMN #{column.to_sql}"
18
+ end
19
+
20
+ def drop_column(name)
21
+ # raise NotImplemented for SQLite3. Can't ALTER TABLE, need to copy table.
22
+ # We'd have to inspect it, and we can't, since we aren't executing any queries yet.
23
+ # TODO instead of building the SQL queries when executing the block, create AddColumn,
24
+ # AlterColumn and DropColumn objects that get #to_sql'd
25
+ if name.is_a?(Array)
26
+ name.each{ |n| drop_column(n) }
27
+ else
28
+ @statements << "ALTER TABLE #{quoted_table_name} DROP COLUMN #{quote_column_name(name)}"
29
+ end
30
+ end
31
+ alias drop_columns drop_column
32
+
33
+ def rename_column(name, new_name, opts = {})
34
+ # raise NotImplemented for SQLite3
35
+ @statements << "ALTER TABLE #{quoted_table_name} RENAME COLUMN #{quote_column_name(name)} TO #{quote_column_name(new_name)}"
36
+ end
37
+
38
+ def change_column(name, type, opts = {})
39
+ # raise NotImplemented for SQLite3
40
+ @statements << "ALTER TABLE #{quoted_table_name} ALTER COLUMN #{quote_column_name(name)} TYPE #{type}"
41
+ end
42
+
43
+ def quote_column_name(name)
44
+ @adapter.send(:quote_name, name.to_s)
45
+ end
46
+
47
+ def quoted_table_name
48
+ @adapter.send(:quote_name, table_name)
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,73 @@
1
+ require 'spec/matchers/migration_matchers'
2
+
3
+ require 'spec'
4
+
5
+ module Spec
6
+ module Example
7
+ class MigrationExampleGroup < Spec::Example::ExampleGroup
8
+ include Spec::Matchers::Migration
9
+
10
+ before(:all) do
11
+ if this_migration.adapter.supports_schema_transactions?
12
+ run_prereq_migrations
13
+ end
14
+ end
15
+
16
+ before(:each) do
17
+ if ! this_migration.adapter.supports_schema_transactions?
18
+ run_prereq_migrations
19
+ else
20
+ this_migration.adapter.begin_transaction
21
+ end
22
+ end
23
+
24
+ after(:each) do
25
+ if this_migration.adapter.supports_schema_transactions?
26
+ this_migration.adapter.rollback_transaction
27
+ end
28
+ end
29
+
30
+ after(:all) do
31
+ this_migration.adapter.recreate_database
32
+ end
33
+
34
+ def run_prereq_migrations
35
+ "running n-1 migrations"
36
+ all_databases.each do |db|
37
+ db.adapter.recreate_database
38
+ end
39
+ @@migrations.sort.each do |migration|
40
+ break if migration.name.to_s == migration_name.to_s
41
+ migration.perform_up
42
+ end
43
+ end
44
+
45
+ def run_migration
46
+ this_migration.perform_up
47
+ end
48
+
49
+ def migration_name
50
+ @migration_name ||= self.class.instance_variable_get("@description_text").to_s
51
+ end
52
+
53
+ def all_databases
54
+ @@migrations.map { |m| m.database }.uniq
55
+ end
56
+
57
+ def this_migration
58
+ @@migrations.select { |m| m.name.to_s == migration_name }.first
59
+ end
60
+
61
+ def select(sql)
62
+ this_migration.adapter.select(sql)
63
+ end
64
+
65
+ def table(table_name)
66
+ this_migration.adapter.table(table_name)
67
+ end
68
+
69
+ Spec::Example::ExampleGroupFactory.register(:migration, self)
70
+
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,106 @@
1
+ module Spec
2
+ module Matchers
3
+ module Migration
4
+
5
+ def have_table(table_name)
6
+ HaveTableMatcher.new(table_name)
7
+ end
8
+
9
+ def have_column(column_name)
10
+ HaveColumnMatcher.new(column_name)
11
+ end
12
+
13
+ def permit_null
14
+ NullableColumnMatcher.new
15
+ end
16
+
17
+ def be_primary_key
18
+ PrimaryKeyMatcher.new
19
+ end
20
+
21
+ class HaveTableMatcher
22
+
23
+ attr_accessor :table_name, :repository
24
+
25
+ def initialize(table_name)
26
+ @table_name = table_name
27
+ end
28
+
29
+ def matches?(repository)
30
+ repository.adapter.storage_exists?(table_name)
31
+ end
32
+
33
+ def failure_message
34
+ %(expected #{repository} to have table '#{table_name}')
35
+ end
36
+
37
+ def negative_failure_message
38
+ %(expected #{repository} to not have table '#{table_name}')
39
+ end
40
+
41
+ end
42
+
43
+ class HaveColumnMatcher
44
+
45
+ attr_accessor :table, :column_name
46
+
47
+ def initialize(column_name)
48
+ @column_name = column_name
49
+ end
50
+
51
+ def matches?(table)
52
+ @table = table
53
+ table.columns.map { |c| c.name }.include?(column_name.to_s)
54
+ end
55
+
56
+ def failure_message
57
+ %(expected #{table} to have column '#{column_name}')
58
+ end
59
+
60
+ def negative_failure_message
61
+ %(expected #{table} to not have column '#{column_name}')
62
+ end
63
+
64
+ end
65
+
66
+ class NullableColumnMatcher
67
+
68
+ attr_accessor :column
69
+
70
+ def matches?(column)
71
+ @column = column
72
+ ! column.not_null
73
+ end
74
+
75
+ def failure_message
76
+ %(expected #{column.name} to permit NULL)
77
+ end
78
+
79
+ def negative_failure_message
80
+ %(expected #{column.name} to be NOT NULL)
81
+ end
82
+
83
+ end
84
+
85
+ class PrimaryKeyMatcher
86
+
87
+ attr_accessor :column
88
+
89
+ def matches?(column)
90
+ @column = column
91
+ column.primary_key
92
+ end
93
+
94
+ def failure_message
95
+ %(expected #{column.name} to be PRIMARY KEY)
96
+ end
97
+
98
+ def negative_failure_message
99
+ %(expected #{column.name} to not be PRIMARY KEY)
100
+ end
101
+
102
+ end
103
+
104
+ end
105
+ end
106
+ 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