sbf-dm-migrations 1.3.0.beta

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 (62) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +38 -0
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +468 -0
  5. data/.travis.yml +52 -0
  6. data/Gemfile +61 -0
  7. data/LICENSE +20 -0
  8. data/README.rdoc +39 -0
  9. data/Rakefile +4 -0
  10. data/db/migrations/1_create_people_table.rb +12 -0
  11. data/db/migrations/2_add_dob_to_people.rb +13 -0
  12. data/db/migrations/config.rb +4 -0
  13. data/dm-migrations.gemspec +20 -0
  14. data/examples/Rakefile +149 -0
  15. data/examples/sample_migration.rb +58 -0
  16. data/examples/sample_migration_spec.rb +46 -0
  17. data/lib/dm-migrations/adapters/dm-do-adapter.rb +304 -0
  18. data/lib/dm-migrations/adapters/dm-mysql-adapter.rb +306 -0
  19. data/lib/dm-migrations/adapters/dm-oracle-adapter.rb +339 -0
  20. data/lib/dm-migrations/adapters/dm-postgres-adapter.rb +152 -0
  21. data/lib/dm-migrations/adapters/dm-sqlite-adapter.rb +88 -0
  22. data/lib/dm-migrations/adapters/dm-sqlserver-adapter.rb +184 -0
  23. data/lib/dm-migrations/adapters/dm-yaml-adapter.rb +21 -0
  24. data/lib/dm-migrations/auto_migration.rb +227 -0
  25. data/lib/dm-migrations/exceptions/duplicate_migration.rb +6 -0
  26. data/lib/dm-migrations/migration.rb +323 -0
  27. data/lib/dm-migrations/migration_runner.rb +76 -0
  28. data/lib/dm-migrations/sql/column.rb +5 -0
  29. data/lib/dm-migrations/sql/mysql.rb +84 -0
  30. data/lib/dm-migrations/sql/oracle.rb +9 -0
  31. data/lib/dm-migrations/sql/postgres.rb +89 -0
  32. data/lib/dm-migrations/sql/sqlite.rb +59 -0
  33. data/lib/dm-migrations/sql/sqlserver.rb +9 -0
  34. data/lib/dm-migrations/sql/table.rb +15 -0
  35. data/lib/dm-migrations/sql/table_creator.rb +105 -0
  36. data/lib/dm-migrations/sql/table_modifier.rb +57 -0
  37. data/lib/dm-migrations/sql.rb +7 -0
  38. data/lib/dm-migrations/version.rb +5 -0
  39. data/lib/dm-migrations.rb +3 -0
  40. data/lib/spec/example/migration_example_group.rb +69 -0
  41. data/lib/spec/matchers/migration_matchers.rb +96 -0
  42. data/spec/integration/auto_migration_spec.rb +590 -0
  43. data/spec/integration/auto_upgrade_spec.rb +41 -0
  44. data/spec/integration/migration_runner_spec.rb +84 -0
  45. data/spec/integration/migration_spec.rb +156 -0
  46. data/spec/integration/sql_spec.rb +290 -0
  47. data/spec/isolated/require_after_setup_spec.rb +24 -0
  48. data/spec/isolated/require_before_setup_spec.rb +24 -0
  49. data/spec/isolated/require_spec.rb +23 -0
  50. data/spec/spec_helper.rb +16 -0
  51. data/spec/unit/migration_spec.rb +501 -0
  52. data/spec/unit/sql/column_spec.rb +14 -0
  53. data/spec/unit/sql/postgres_spec.rb +90 -0
  54. data/spec/unit/sql/sqlite_extensions_spec.rb +103 -0
  55. data/spec/unit/sql/table_creator_spec.rb +91 -0
  56. data/spec/unit/sql/table_modifier_spec.rb +47 -0
  57. data/spec/unit/sql/table_spec.rb +26 -0
  58. data/spec/unit/sql_spec.rb +7 -0
  59. data/tasks/spec.rake +21 -0
  60. data/tasks/yard.rake +9 -0
  61. data/tasks/yardstick.rake +19 -0
  62. metadata +120 -0
@@ -0,0 +1,306 @@
1
+ require 'dm-migrations/auto_migration'
2
+ require 'dm-migrations/adapters/dm-do-adapter'
3
+
4
+ module DataMapper
5
+ module Migrations
6
+ module MysqlAdapter
7
+ DEFAULT_ENGINE = 'InnoDB'.freeze
8
+ DEFAULT_CHARACTER_SET = 'utf8'.freeze
9
+ DEFAULT_COLLATION = 'utf8_unicode_ci'.freeze
10
+ MAXIMUM_CHAR_LENGTH = ((2**16) - 1) / 4 # allow room for utf8mb4
11
+
12
+ include SQL, DataObjectsAdapter
13
+
14
+ # @api private
15
+ def self.included(base)
16
+ base.extend DataObjectsAdapter::ClassMethods
17
+ base.extend ClassMethods
18
+ end
19
+
20
+ # @api semipublic
21
+ def storage_exists?(storage_name)
22
+ select('SHOW TABLES LIKE ?', storage_name).first == storage_name
23
+ end
24
+
25
+ # @api semipublic
26
+ def field_exists?(storage_name, field)
27
+ result = select("SHOW COLUMNS FROM #{quote_name(storage_name)} LIKE ?", field).first
28
+ result ? result.field == field : false
29
+ end
30
+
31
+ module SQL # :nodoc:
32
+ # private ## This cannot be private for current migrations
33
+
34
+ # Allows for specification of the default storage engine to use when creating tables via
35
+ # migrations. Defaults to DEFAULT_ENGINE.
36
+ #
37
+ # adapter = DataMapper.setup(:default, 'mysql://localhost/foo')
38
+ # adapter.storage_engine = 'MyISAM'
39
+ #
40
+ # @api public
41
+ attr_accessor :storage_engine
42
+
43
+ # @api private
44
+ def supports_serial?
45
+ true
46
+ end
47
+
48
+ # @api private
49
+ def supports_drop_table_if_exists?
50
+ true
51
+ end
52
+
53
+ # @api private
54
+ def schema_name
55
+ # TODO: is there a cleaner way to find out the current DB we are connected to?
56
+ normalized_uri.path.split('/').last
57
+ end
58
+
59
+ # @api private
60
+ def create_table_statement(connection, model, properties)
61
+ "#{super} ENGINE = #{storage_engine} CHARACTER SET #{character_set} COLLATE #{collation}"
62
+ end
63
+
64
+ # @api private
65
+ def property_schema_hash(property)
66
+ schema = super
67
+
68
+ case property.dump_as
69
+ when Integer.singleton_class
70
+ if property.respond_to?(:min) && property.respond_to?(:max)
71
+ min = property.min
72
+ max = property.max
73
+ schema[:primitive] = integer_column_statement(min..max) if min && max
74
+ end
75
+ when String.singleton_class
76
+ if property.is_a?(Property::Text)
77
+ schema[:primitive] = text_column_statement(property.length)
78
+ schema.delete(:default)
79
+ else
80
+ schema[:length] ||= MAXIMUM_CHAR_LENGTH
81
+ end
82
+ end
83
+
84
+ schema
85
+ end
86
+
87
+ # @api private
88
+ def property_schema_statement(connection, schema)
89
+ statement = super
90
+
91
+ statement << ' AUTO_INCREMENT' if supports_serial? && schema[:serial]
92
+
93
+ statement
94
+ end
95
+
96
+ # @api private
97
+ def storage_engine
98
+ # Don't pull the default engine via show_variable for backwards compat where it was hard
99
+ # coded to InnoDB
100
+ @storage_engine ||= DEFAULT_ENGINE
101
+ end
102
+
103
+ # @api private
104
+ def character_set
105
+ @character_set ||= show_variable('character_set_connection') || DEFAULT_CHARACTER_SET
106
+ end
107
+
108
+ # @api private
109
+ def collation
110
+ @collation ||= show_variable('collation_connection') || DEFAULT_COLLATION
111
+ end
112
+
113
+ # @api private
114
+ def show_variable(name)
115
+ result = select('SHOW VARIABLES LIKE ?', name).first
116
+ result ? result.value.freeze : nil
117
+ end
118
+
119
+ # Return SQL statement for the text column
120
+ #
121
+ # @param [Integer] length
122
+ # the max allowed length
123
+ #
124
+ # @return [String]
125
+ # the statement to create the text column
126
+ #
127
+ # @api private
128
+ private def text_column_statement(length)
129
+ if length < 2**8
130
+ 'TINYTEXT'
131
+ elsif length < 2**16
132
+ 'TEXT'
133
+ elsif length < 2**24
134
+ 'MEDIUMTEXT'
135
+ elsif length < 2**32
136
+ 'LONGTEXT'
137
+
138
+ # http://www.postgresql.org/files/documentation/books/aw_pgsql/node90.html
139
+ # Implies that PostgreSQL doesn't have a size limit on text
140
+ # fields, so this param validation happens here instead of
141
+ # DM::Property#initialize.
142
+ else
143
+ raise ArgumentError, "length of #{length} exceeds maximum size supported"
144
+ end
145
+ end
146
+
147
+ # Return SQL statement for the integer column
148
+ #
149
+ # @param [Range] range
150
+ # the min/max allowed integers
151
+ #
152
+ # @return [String]
153
+ # the statement to create the integer column
154
+ #
155
+ # @api private
156
+ private def integer_column_statement(range)
157
+ format('%s(%d)%s', integer_column_type(range), integer_display_size(range), integer_statement_sign(range))
158
+ end
159
+
160
+ # Return the integer column type
161
+ #
162
+ # Use the smallest available column type that will satisfy the
163
+ # allowable range of numbers
164
+ #
165
+ # @param [Range] range
166
+ # the min/max allowed integers
167
+ #
168
+ # @return [String]
169
+ # the column type
170
+ #
171
+ # @api private
172
+ private def integer_column_type(range)
173
+ if range.first < 0
174
+ signed_integer_column_type(range)
175
+ else
176
+ unsigned_integer_column_type(range)
177
+ end
178
+ end
179
+
180
+ # Return the signed integer column type
181
+ #
182
+ # @param [Range] range
183
+ # the min/max allowed integers
184
+ #
185
+ # @return [String]
186
+ #
187
+ # @api private
188
+ private def signed_integer_column_type(range)
189
+ min = range.first
190
+ max = range.last
191
+
192
+ tinyint = 2**7
193
+ smallint = 2**15
194
+ integer = 2**31
195
+ mediumint = 2**23
196
+ bigint = 2**63
197
+
198
+ if min >= -tinyint && max < tinyint
199
+ 'TINYINT'
200
+ elsif min >= -smallint && max < smallint
201
+ 'SMALLINT'
202
+ elsif min >= -mediumint && max < mediumint
203
+ 'MEDIUMINT'
204
+ elsif min >= -integer && max < integer
205
+ 'INT'
206
+ elsif min >= -bigint && max < bigint
207
+ 'BIGINT'
208
+ else
209
+ raise ArgumentError, "min #{min} and max #{max} exceeds supported range"
210
+ end
211
+ end
212
+
213
+ # Return the unsigned integer column type
214
+ #
215
+ # @param [Range] range
216
+ # the min/max allowed integers
217
+ #
218
+ # @return [String]
219
+ #
220
+ # @api private
221
+ private def unsigned_integer_column_type(range)
222
+ max = range.last
223
+
224
+ if max < 2**8
225
+ 'TINYINT'
226
+ elsif max < 2**16
227
+ 'SMALLINT'
228
+ elsif max < 2**24
229
+ 'MEDIUMINT'
230
+ elsif max < 2**32
231
+ 'INT'
232
+ elsif max < 2**64
233
+ 'BIGINT'
234
+ else
235
+ raise ArgumentError, "min #{range.first} and max #{max} exceeds supported range"
236
+ end
237
+ end
238
+
239
+ # Return the integer column display size
240
+ #
241
+ # Adjust the display size to match the maximum number of
242
+ # expected digits. This is more for documentation purposes
243
+ # and does not affect what can actually be stored in a
244
+ # specific column
245
+ #
246
+ # @param [Range] range
247
+ # the min/max allowed integers
248
+ #
249
+ # @return [Integer]
250
+ # the display size for the integer
251
+ #
252
+ # @api private
253
+ private def integer_display_size(range)
254
+ [range.first.to_s.length, range.last.to_s.length].max
255
+ end
256
+
257
+ # Return the integer sign statement
258
+ #
259
+ # @param [Range] range
260
+ # the min/max allowed integers
261
+ #
262
+ # @return [String, nil]
263
+ # statement if unsigned, nil if signed
264
+ #
265
+ # @api private
266
+ private def integer_statement_sign(range)
267
+ ' UNSIGNED' unless range.first < 0
268
+ end
269
+
270
+ # @api private
271
+ private def indexes(model)
272
+ filter_indexes(model, super)
273
+ end
274
+
275
+ # @api private
276
+ private def unique_indexes(model)
277
+ filter_indexes(model, super)
278
+ end
279
+
280
+ # Filter out any indexes with a non index-able column in MySQL
281
+ #
282
+ # @api private
283
+ private def filter_indexes(model, indexes)
284
+ field_map = model.properties(name).field_map
285
+ indexes.select do |_index_name, fields|
286
+ fields.all? { |field| !field_map[field].is_a?(Property::Text) }
287
+ end
288
+ end
289
+ end
290
+
291
+ module ClassMethods
292
+ # Types for MySQL databases.
293
+ #
294
+ # @return [Hash] types for MySQL databases.
295
+ #
296
+ # @api private
297
+ def type_map
298
+ super.merge(
299
+ DateTime => {primitive: 'DATETIME'},
300
+ Time => {primitive: 'DATETIME'}
301
+ ).freeze
302
+ end
303
+ end
304
+ end
305
+ end
306
+ end
@@ -0,0 +1,339 @@
1
+ require 'dm-migrations/auto_migration'
2
+ require 'dm-migrations/adapters/dm-do-adapter'
3
+
4
+ module DataMapper
5
+ module Migrations
6
+ module OracleAdapter
7
+ include SQL, DataObjectsAdapter
8
+
9
+ # @api private
10
+ def self.included(base)
11
+ base.extend DataObjectsAdapter::ClassMethods
12
+ base.extend ClassMethods
13
+ end
14
+
15
+ # @api semipublic
16
+ def storage_exists?(storage_name)
17
+ statement = DataMapper::Ext::String.compress_lines(<<-SQL)
18
+ SELECT COUNT(*)
19
+ FROM all_tables
20
+ WHERE owner = ?
21
+ AND table_name = ?
22
+ SQL
23
+
24
+ select(statement, schema_name, oracle_upcase(storage_name)).first > 0
25
+ end
26
+
27
+ # @api semipublic
28
+ def sequence_exists?(sequence_name)
29
+ return false unless sequence_name
30
+
31
+ statement = DataMapper::Ext::String.compress_lines(<<-SQL)
32
+ SELECT COUNT(*)
33
+ FROM all_sequences
34
+ WHERE sequence_owner = ?
35
+ AND sequence_name = ?
36
+ SQL
37
+
38
+ select(statement, schema_name, oracle_upcase(sequence_name)).first > 0
39
+ end
40
+
41
+ # @api semipublic
42
+ def field_exists?(storage_name, field_name)
43
+ statement = DataMapper::Ext::String.compress_lines(<<-SQL)
44
+ SELECT COUNT(*)
45
+ FROM all_tab_columns
46
+ WHERE owner = ?
47
+ AND table_name = ?
48
+ AND column_name = ?
49
+ SQL
50
+
51
+ select(statement, schema_name, oracle_upcase(storage_name), oracle_upcase(field_name)).first > 0
52
+ end
53
+
54
+ # @api semipublic
55
+ def storage_fields(storage_name)
56
+ statement = DataMapper::Ext::String.compress_lines(<<-SQL)
57
+ SELECT column_name
58
+ FROM all_tab_columns
59
+ WHERE owner = ?
60
+ AND table_name = ?
61
+ SQL
62
+
63
+ select(statement, schema_name, oracle_upcase(storage_name))
64
+ end
65
+
66
+ def drop_table_statement(model)
67
+ table_name = quote_name(model.storage_name(name))
68
+ "DROP TABLE #{table_name} CASCADE CONSTRAINTS"
69
+ end
70
+
71
+ # @api semipublic
72
+ def create_model_storage(model)
73
+ name = self.name
74
+ properties = model.properties_with_subclasses(name)
75
+ table_name = model.storage_name(name)
76
+ truncate_or_delete = self.class.auto_migrate_with
77
+ table_is_truncated = truncate_or_delete && @truncated_tables && @truncated_tables[table_name]
78
+
79
+ return false if storage_exists?(table_name) && !table_is_truncated
80
+ return false if properties.empty?
81
+
82
+ with_connection do |connection|
83
+ # if table was truncated then check if all columns for properties are present
84
+ # TODO: check all other column definition options
85
+ if table_is_truncated && storage_has_all_fields?(table_name, properties)
86
+ @truncated_tables[table_name] = nil
87
+ else
88
+ # forced drop of table if properties are different
89
+ destroy_model_storage(model, true) if truncate_or_delete
90
+
91
+ statements = [create_table_statement(connection, model, properties)]
92
+ statements.concat(create_index_statements(model))
93
+ statements.concat(create_unique_index_statements(model))
94
+ statements.concat(create_sequence_statements(model))
95
+
96
+ statements.each do |statement|
97
+ command = connection.create_command(statement)
98
+ command.execute_non_query
99
+ end
100
+ end
101
+ end
102
+
103
+ true
104
+ end
105
+
106
+ # @api semipublic
107
+ def destroy_model_storage(model, forced = false)
108
+ table_name = model.storage_name(name)
109
+ klass = self.class
110
+ truncate_or_delete = klass.auto_migrate_with
111
+ if storage_exists?(table_name)
112
+ if truncate_or_delete && !forced
113
+ case truncate_or_delete
114
+ when :truncate
115
+ execute(truncate_table_statement(model))
116
+ when :delete
117
+ execute(delete_table_statement(model))
118
+ else
119
+ raise ArgumentError, 'Unsupported auto_migrate_with option'
120
+ end
121
+ @truncated_tables ||= {}
122
+ @truncated_tables[table_name] = true
123
+ else
124
+ execute(drop_table_statement(model))
125
+ @truncated_tables[table_name] = nil if @truncated_tables
126
+ end
127
+ end
128
+ # added destroy of sequences
129
+ reset_sequences = klass.auto_migrate_reset_sequences
130
+ table_is_truncated = @truncated_tables && @truncated_tables[table_name]
131
+ unless truncate_or_delete && !reset_sequences && !forced
132
+ if sequence_exists?(model_sequence_name(model))
133
+ statement = if table_is_truncated && !forced
134
+ reset_sequence_statement(model)
135
+ else
136
+ drop_sequence_statement(model)
137
+ end
138
+ execute(statement) if statement
139
+ end
140
+ end
141
+ true
142
+ end
143
+
144
+ private def storage_has_all_fields?(table_name, properties)
145
+ properties.map { |property| oracle_upcase(property.field) }.sort == storage_fields(table_name).sort
146
+ end
147
+
148
+ # If table or column name contains just lowercase characters then do uppercase
149
+ # as uppercase version will be used in Oracle data dictionary tables
150
+ private def oracle_upcase(name)
151
+ (name =~ /[A-Z]/) ? name : name.upcase
152
+ end
153
+
154
+ module SQL # :nodoc:
155
+ # private ## This cannot be private for current migrations
156
+
157
+ # @api private
158
+ def schema_name
159
+ @schema_name ||= select("SELECT SYS_CONTEXT('userenv','current_schema') FROM dual").first.freeze
160
+ end
161
+
162
+ # @api private
163
+ def property_schema_hash(property)
164
+ schema = super
165
+
166
+ if property.is_a?(Property::Binary)
167
+ # BLOB does not support length
168
+ schema.delete(:length)
169
+ end
170
+
171
+ if property.primitive == String && property.length > 4000
172
+ # Oracle doesn't support string over 4000 bytes
173
+ schema[:primitive] = 'NCLOB'
174
+ # CLOB and NCLOB do not support length
175
+ schema.delete(:length)
176
+ end
177
+
178
+ schema
179
+ end
180
+
181
+ # @api private
182
+ def create_sequence_statements(model)
183
+ name = self.name
184
+ table_name = model.storage_name(name)
185
+ serial = model.serial(name)
186
+
187
+ statements = []
188
+ if (sequence_name = model_sequence_name(model))
189
+ sequence_name = quote_name(sequence_name)
190
+ column_name = quote_name(serial.field)
191
+
192
+ statements << DataMapper::Ext::String.compress_lines(<<-SQL)
193
+ CREATE SEQUENCE #{sequence_name} NOCACHE
194
+ SQL
195
+
196
+ # create trigger only if custom sequence name was not specified
197
+ unless serial.options[:sequence]
198
+ statements << DataMapper::Ext::String.compress_lines(<<-SQL)
199
+ CREATE OR REPLACE TRIGGER #{quote_name(default_trigger_name(table_name))}
200
+ BEFORE INSERT ON #{quote_name(table_name)} FOR EACH ROW
201
+ BEGIN
202
+ IF inserting THEN
203
+ IF :new.#{column_name} IS NULL THEN
204
+ SELECT #{sequence_name}.NEXTVAL INTO :new.#{column_name} FROM dual;
205
+ END IF;
206
+ END IF;
207
+ END;
208
+ SQL
209
+ end
210
+ end
211
+
212
+ statements
213
+ end
214
+
215
+ # @api private
216
+ def drop_sequence_statement(model)
217
+ return unless (sequence_name = model_sequence_name(model))
218
+
219
+ "DROP SEQUENCE #{quote_name(sequence_name)}"
220
+ end
221
+
222
+ # @api private
223
+ def reset_sequence_statement(model)
224
+ return unless (sequence_name = model_sequence_name(model))
225
+
226
+ sequence_name = quote_name(sequence_name)
227
+ DataMapper::Ext::String.compress_lines(<<-SQL)
228
+ DECLARE
229
+ cval INTEGER;
230
+ BEGIN
231
+ SELECT #{sequence_name}.NEXTVAL INTO cval FROM dual;
232
+ EXECUTE IMMEDIATE 'ALTER SEQUENCE #{sequence_name} INCREMENT BY -' || cval || ' MINVALUE 0';
233
+ SELECT #{sequence_name}.NEXTVAL INTO cval FROM dual;
234
+ EXECUTE IMMEDIATE 'ALTER SEQUENCE #{sequence_name} INCREMENT BY 1';
235
+ END;
236
+ SQL
237
+ end
238
+
239
+ # @api private
240
+ def truncate_table_statement(model)
241
+ "TRUNCATE TABLE #{quote_name(model.storage_name(name))}"
242
+ end
243
+
244
+ # @api private
245
+ def delete_table_statement(model)
246
+ "DELETE FROM #{quote_name(model.storage_name(name))}"
247
+ end
248
+
249
+ private def model_sequence_name(model)
250
+ name = self.name
251
+ table_name = model.storage_name(name)
252
+ serial = model.serial(name)
253
+
254
+ return unless serial
255
+
256
+ serial.options[:sequence] || default_sequence_name(table_name)
257
+ end
258
+
259
+ private def default_sequence_name(table_name)
260
+ # truncate table name if necessary to fit in max length of identifier
261
+ "#{table_name[0, self.class::IDENTIFIER_MAX_LENGTH - 4]}_seq"
262
+ end
263
+
264
+ private def default_trigger_name(table_name)
265
+ # truncate table name if necessary to fit in max length of identifier
266
+ "#{table_name[0, self.class::IDENTIFIER_MAX_LENGTH - 4]}_pkt"
267
+ end
268
+
269
+ # @api private
270
+ private def add_column_statement
271
+ 'ADD'
272
+ end
273
+ end
274
+
275
+ module ClassMethods
276
+ # Types for Oracle databases.
277
+ #
278
+ # @return [Hash] types for Oracle databases.
279
+ #
280
+ # @api private
281
+ def type_map
282
+ length = Property::String.length
283
+ precision = Property::Numeric.precision
284
+ _scale = Property::Decimal.scale
285
+
286
+ super.merge(
287
+ Integer => {primitive: 'NUMBER', precision: precision, scale: 0},
288
+ String => {primitive: 'VARCHAR2', length: length},
289
+ Class => {primitive: 'VARCHAR2', length: length},
290
+ BigDecimal => {primitive: 'NUMBER', precision: precision, scale: nil},
291
+ Float => {primitive: 'BINARY_FLOAT'},
292
+ DateTime => {primitive: 'DATE'},
293
+ Date => {primitive: 'DATE'},
294
+ Time => {primitive: 'DATE'},
295
+ TrueClass => {primitive: 'NUMBER', precision: 1, scale: 0},
296
+ Property::Text => {primitive: 'CLOB'}
297
+ ).freeze
298
+ end
299
+
300
+ # Use table truncate or delete for auto_migrate! to speed up test execution
301
+ #
302
+ # @param [Symbol] :truncate, :delete or :drop_and_create (or nil)
303
+ # do not specify parameter to return current value
304
+ #
305
+ # @return [Mixed]
306
+ # [Symbol] current value of auto_migrate_with option
307
+ # (nil returned for :drop_and_create)
308
+ #
309
+ # @api semipublic
310
+ def auto_migrate_with(value = :not_specified)
311
+ return @auto_migrate_with if value == :not_specified
312
+
313
+ value = nil if value == :drop_and_create
314
+ raise ArgumentError unless [nil, :truncate, :delete].include?(value)
315
+
316
+ @auto_migrate_with = value
317
+ end
318
+
319
+ # Set if sequences will or will not be reset during auto_migrate!
320
+ #
321
+ # @param [Mixed] value
322
+ # reset sequences? TrueClass, FalseClass
323
+ # do not specify parameter to return current value
324
+ #
325
+ # @return [Mixed]
326
+ # [Symbol] current value of auto_migrate_reset_sequences option
327
+ # (default value is true)
328
+ #
329
+ # @api semipublic
330
+ def auto_migrate_reset_sequences(value = :not_specified)
331
+ return @auto_migrate_reset_sequences.nil? ? true : @auto_migrate_reset_sequences if value == :not_specified
332
+ raise ArgumentError unless [true, false].include?(value)
333
+
334
+ @auto_migrate_reset_sequences = value
335
+ end
336
+ end
337
+ end
338
+ end
339
+ end