dm-hibernate-migrations 1.0.0

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 (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