declare_schema 0.10.0 → 0.10.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -1
- data/Gemfile.lock +1 -1
- data/lib/declare_schema/model/foreign_key_definition.rb +4 -8
- data/lib/declare_schema/model/index_definition.rb +0 -19
- data/lib/declare_schema/schema_change/all.rb +22 -0
- data/lib/declare_schema/schema_change/base.rb +45 -0
- data/lib/declare_schema/schema_change/column_add.rb +27 -0
- data/lib/declare_schema/schema_change/column_change.rb +32 -0
- data/lib/declare_schema/schema_change/column_remove.rb +20 -0
- data/lib/declare_schema/schema_change/column_rename.rb +23 -0
- data/lib/declare_schema/schema_change/foreign_key_add.rb +25 -0
- data/lib/declare_schema/schema_change/foreign_key_remove.rb +20 -0
- data/lib/declare_schema/schema_change/index_add.rb +33 -0
- data/lib/declare_schema/schema_change/index_remove.rb +20 -0
- data/lib/declare_schema/schema_change/primary_key_change.rb +33 -0
- data/lib/declare_schema/schema_change/table_add.rb +37 -0
- data/lib/declare_schema/schema_change/table_change.rb +36 -0
- data/lib/declare_schema/schema_change/table_remove.rb +22 -0
- data/lib/declare_schema/schema_change/table_rename.rb +22 -0
- data/lib/declare_schema/version.rb +1 -1
- data/lib/generators/declare_schema/migration/migrator.rb +172 -174
- data/spec/lib/declare_schema/interactive_primary_key_spec.rb +52 -14
- data/spec/lib/declare_schema/migration_generator_spec.rb +175 -303
- data/spec/lib/declare_schema/model/foreign_key_definition_spec.rb +0 -12
- data/spec/lib/declare_schema/schema_change/base_spec.rb +75 -0
- data/spec/lib/declare_schema/schema_change/column_add_spec.rb +30 -0
- data/spec/lib/declare_schema/schema_change/column_change_spec.rb +33 -0
- data/spec/lib/declare_schema/schema_change/column_remove_spec.rb +30 -0
- data/spec/lib/declare_schema/schema_change/column_rename_spec.rb +28 -0
- data/spec/lib/declare_schema/schema_change/foreign_key_add_spec.rb +29 -0
- data/spec/lib/declare_schema/schema_change/foreign_key_remove_spec.rb +29 -0
- data/spec/lib/declare_schema/schema_change/index_add_spec.rb +56 -0
- data/spec/lib/declare_schema/schema_change/index_remove_spec.rb +29 -0
- data/spec/lib/declare_schema/schema_change/primary_key_change_spec.rb +69 -0
- data/spec/lib/declare_schema/schema_change/table_add_spec.rb +50 -0
- data/spec/lib/declare_schema/schema_change/table_change_spec.rb +30 -0
- data/spec/lib/declare_schema/schema_change/table_remove_spec.rb +27 -0
- data/spec/lib/declare_schema/schema_change/table_rename_spec.rb +27 -0
- data/spec/lib/generators/declare_schema/migration/migrator_spec.rb +59 -11
- data/spec/support/acceptance_spec_helpers.rb +2 -2
- metadata +34 -5
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base'
|
4
|
+
|
5
|
+
module DeclareSchema
|
6
|
+
module SchemaChange
|
7
|
+
class TableChange < Base
|
8
|
+
def initialize(table_name, old_options, new_options)
|
9
|
+
@table_name = table_name
|
10
|
+
@old_options = old_options
|
11
|
+
@new_options = new_options
|
12
|
+
end
|
13
|
+
|
14
|
+
def up_command
|
15
|
+
alter_table(@table_name, @new_options)
|
16
|
+
end
|
17
|
+
|
18
|
+
def down_command
|
19
|
+
alter_table(@table_name, @old_options)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
TABLE_OPTIONS_TO_SQL_MAPPINGS = {
|
25
|
+
charset: 'CHARACTER SET',
|
26
|
+
collation: 'COLLATE'
|
27
|
+
}.freeze
|
28
|
+
|
29
|
+
def alter_table(table_name, options)
|
30
|
+
sql_options = options.map { |key, value| [TABLE_OPTIONS_TO_SQL_MAPPINGS[key], value] }
|
31
|
+
statement = "ALTER TABLE #{ActiveRecord::Base.connection.quote_table_name(table_name)} #{sql_options.join(' ')}"
|
32
|
+
"execute #{statement.inspect}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base'
|
4
|
+
|
5
|
+
module DeclareSchema
|
6
|
+
module SchemaChange
|
7
|
+
class TableRemove < Base
|
8
|
+
def initialize(table_name, add_table_back)
|
9
|
+
@table_name = table_name
|
10
|
+
@add_table_back = add_table_back
|
11
|
+
end
|
12
|
+
|
13
|
+
def up_command
|
14
|
+
"drop_table #{@table_name.to_sym.inspect}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def down_command
|
18
|
+
@add_table_back
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base'
|
4
|
+
|
5
|
+
module DeclareSchema
|
6
|
+
module SchemaChange
|
7
|
+
class TableRename < Base
|
8
|
+
def initialize(old_name, new_name)
|
9
|
+
@old_name = old_name
|
10
|
+
@new_name = new_name
|
11
|
+
end
|
12
|
+
|
13
|
+
def up_command
|
14
|
+
"rename_table #{@old_name.to_sym.inspect}, #{@new_name.to_sym.inspect}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def down_command
|
18
|
+
"rename_table #{@new_name.to_sym.inspect}, #{@old_name.to_sym.inspect}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'active_record'
|
4
4
|
require 'active_record/connection_adapters/abstract_adapter'
|
5
|
+
require 'declare_schema/schema_change/all'
|
5
6
|
|
6
7
|
module Generators
|
7
8
|
module DeclareSchema
|
@@ -24,9 +25,7 @@ module Generators
|
|
24
25
|
end
|
25
26
|
|
26
27
|
def run(renames = {})
|
27
|
-
|
28
|
-
g.renames = renames
|
29
|
-
g.generate
|
28
|
+
Migrator.new(renames: renames).generate
|
30
29
|
end
|
31
30
|
|
32
31
|
def default_migration_name
|
@@ -48,14 +47,12 @@ module Generators
|
|
48
47
|
deprecate :default_charset=, :default_collation=, :default_charset, :default_collation, deprecator: ActiveSupport::Deprecation.new('1.0', 'declare_schema')
|
49
48
|
end
|
50
49
|
|
51
|
-
def initialize(ambiguity_resolver = {})
|
50
|
+
def initialize(ambiguity_resolver = {}, renames: nil)
|
52
51
|
@ambiguity_resolver = ambiguity_resolver
|
53
52
|
@drops = []
|
54
|
-
@renames =
|
53
|
+
@renames = renames
|
55
54
|
end
|
56
55
|
|
57
|
-
attr_accessor :renames
|
58
|
-
|
59
56
|
def load_rails_models
|
60
57
|
ActiveRecord::Migration.verbose = false
|
61
58
|
|
@@ -109,19 +106,24 @@ module Generators
|
|
109
106
|
# return a hash of table renames and modifies the passed arrays so
|
110
107
|
# that renamed tables are no longer listed as to_create or to_drop
|
111
108
|
def extract_table_renames!(to_create, to_drop)
|
112
|
-
if renames
|
109
|
+
if @renames
|
113
110
|
# A hash of table renames has been provided
|
114
111
|
|
115
112
|
to_rename = {}
|
116
|
-
renames.
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
if to_create.delete(new_name.to_s) && to_drop.delete(old_name.to_s)
|
121
|
-
to_rename[old_name.to_s] = new_name.to_s
|
122
|
-
else
|
123
|
-
raise Error, "Invalid table rename specified: #{old_name} => #{new_name}"
|
113
|
+
@renames.each do |old_name, new_name|
|
114
|
+
if new_name.is_a?(Hash)
|
115
|
+
new_name = new_name[:table_name]
|
124
116
|
end
|
117
|
+
new_name or next
|
118
|
+
|
119
|
+
old_name = old_name.to_s
|
120
|
+
new_name = new_name.to_s
|
121
|
+
|
122
|
+
to_create.delete(new_name) or raise Error,
|
123
|
+
"Rename specified new name: #{new_name.inspect} but it was not in the `to_create` list"
|
124
|
+
to_drop.delete(old_name) or raise Error,
|
125
|
+
"Rename specified old name: #{old_name.inspect} but it was not in the `to_drop` list"
|
126
|
+
to_rename[old_name] = new_name
|
125
127
|
end
|
126
128
|
to_rename
|
127
129
|
|
@@ -133,18 +135,22 @@ module Generators
|
|
133
135
|
end
|
134
136
|
end
|
135
137
|
|
138
|
+
# return a hash of column renames and modifies the passed arrays so
|
139
|
+
# that renamed columns are no longer listed as to_create or to_drop
|
136
140
|
def extract_column_renames!(to_add, to_remove, table_name)
|
137
|
-
if renames
|
141
|
+
if @renames
|
138
142
|
to_rename = {}
|
139
|
-
if (column_renames = renames
|
140
|
-
# A hash of
|
141
|
-
|
142
|
-
column_renames.
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
143
|
+
if (column_renames = @renames[table_name.to_sym])
|
144
|
+
# A hash of column renames has been provided
|
145
|
+
|
146
|
+
column_renames.each do |old_name, new_name|
|
147
|
+
old_name = old_name.to_s
|
148
|
+
new_name = new_name.to_s
|
149
|
+
to_add.delete(new_name) or raise Error,
|
150
|
+
"Rename specified new name: #{new_name.inspect} but it was not in the `to_add` list for table #{table_name}"
|
151
|
+
to_remove.delete(old_name) or raise Error,
|
152
|
+
"Rename specified old name: #{old_name.inspect} but it was not in the `to_remove` list for table #{table_name}"
|
153
|
+
to_rename[old_name] = new_name
|
148
154
|
end
|
149
155
|
end
|
150
156
|
to_rename
|
@@ -201,85 +207,103 @@ module Generators
|
|
201
207
|
to_rename = extract_table_renames!(to_create, to_drop)
|
202
208
|
|
203
209
|
renames = to_rename.map do |old_name, new_name|
|
204
|
-
|
205
|
-
end
|
206
|
-
undo_renames = to_rename.map do |old_name, new_name|
|
207
|
-
"rename_table :#{new_name}, :#{old_name}"
|
208
|
-
end * "\n"
|
210
|
+
::DeclareSchema::SchemaChange::TableRename.new(old_name, new_name)
|
211
|
+
end
|
209
212
|
|
210
213
|
drops = to_drop.map do |t|
|
211
|
-
|
212
|
-
end
|
213
|
-
undo_drops = to_drop.map do |t|
|
214
|
-
add_table_back(t)
|
215
|
-
end * "\n\n"
|
214
|
+
::DeclareSchema::SchemaChange::TableRemove.new(t, add_table_back(t))
|
215
|
+
end
|
216
216
|
|
217
217
|
creates = to_create.map do |t|
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
218
|
+
model = models_by_table_name[t]
|
219
|
+
disable_auto_increment = model.try(:disable_auto_increment)
|
220
|
+
|
221
|
+
primary_key_definition =
|
222
|
+
if disable_auto_increment
|
223
|
+
[:integer, :id, limit: 8, auto_increment: false, primary_key: true]
|
224
|
+
end
|
225
|
+
|
226
|
+
field_definitions = model.field_specs.values.sort_by(&:position).map do |f|
|
227
|
+
[f.type, f.name, f.sql_options]
|
228
|
+
end
|
229
|
+
|
230
|
+
table_options_definition = ::DeclareSchema::Model::TableOptionsDefinition.new(model.table_name, table_options_for_model(model))
|
231
|
+
table_options = create_table_options(model, disable_auto_increment)
|
232
|
+
|
233
|
+
table_add = ::DeclareSchema::SchemaChange::TableAdd.new(t,
|
234
|
+
Array(primary_key_definition) + field_definitions,
|
235
|
+
table_options,
|
236
|
+
sql_options: table_options_definition.settings)
|
237
|
+
[
|
238
|
+
table_add,
|
239
|
+
*Array((create_indexes(model) if ::DeclareSchema.default_generate_indexing)),
|
240
|
+
*Array((create_constraints(model) if ::DeclareSchema.default_generate_foreign_keys))
|
241
|
+
]
|
242
|
+
end
|
223
243
|
|
224
244
|
changes = []
|
225
|
-
undo_changes = []
|
226
245
|
index_changes = []
|
227
|
-
undo_index_changes = []
|
228
246
|
fk_changes = []
|
229
|
-
undo_fk_changes = []
|
230
247
|
table_options_changes = []
|
231
|
-
undo_table_options_changes = []
|
232
248
|
|
233
249
|
to_change.each do |t|
|
234
250
|
model = models_by_table_name[t]
|
235
251
|
table = to_rename.key(t) || model.table_name
|
236
252
|
if table.in?(db_tables)
|
237
|
-
change,
|
253
|
+
change, index_change, fk_change, table_options_change = change_table(model, table)
|
238
254
|
changes << change
|
239
|
-
undo_changes << undo
|
240
255
|
index_changes << index_change
|
241
|
-
undo_index_changes << undo_index
|
242
256
|
fk_changes << fk_change
|
243
|
-
undo_fk_changes << undo_fk
|
244
257
|
table_options_changes << table_options_change
|
245
|
-
undo_table_options_changes << undo_table_options_change
|
246
258
|
end
|
247
259
|
end
|
248
260
|
|
249
|
-
|
250
|
-
|
261
|
+
migration_commands = [renames, drops, creates, changes, index_changes, fk_changes, table_options_changes].flatten
|
262
|
+
|
263
|
+
ordered_migration_commands = order_migrations(migration_commands)
|
251
264
|
|
252
|
-
|
265
|
+
up_and_down_migrations(ordered_migration_commands)
|
253
266
|
end
|
254
267
|
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
268
|
+
MIGRATION_ORDER = %w[ TableRename
|
269
|
+
TableAdd
|
270
|
+
TableChange
|
271
|
+
ColumnAdd
|
272
|
+
ColumnRename
|
273
|
+
ColumnChange
|
274
|
+
PrimaryKeyChange
|
275
|
+
IndexAdd
|
276
|
+
ForeignKeyAdd
|
277
|
+
ForeignKeyRemove
|
278
|
+
IndexRemove
|
279
|
+
ColumnRemove
|
280
|
+
TableRemove ]
|
263
281
|
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
282
|
+
def order_migrations(migration_commands)
|
283
|
+
migration_commands.each_with_index.sort_by do |command, index|
|
284
|
+
command_type = command.class.name.gsub(/.*::/, '')
|
285
|
+
priority = MIGRATION_ORDER.index(command_type) or raise "#{command_type.inspect} not found in #{MIGRATION_ORDER.inspect}"
|
286
|
+
[priority, index] # index keeps the sort stable in case of a tie
|
287
|
+
end.map(&:first) # remove the index
|
288
|
+
end
|
289
|
+
|
290
|
+
private
|
291
|
+
|
292
|
+
def up_and_down_migrations(migration_commands)
|
293
|
+
up = migration_commands.map(&:up ).select(&:present?)
|
294
|
+
down = migration_commands.map(&:down).select(&:present?).reverse
|
268
295
|
|
269
|
-
|
270
|
-
#{create_indexes(model).join("\n") if ::DeclareSchema.default_generate_indexing}
|
271
|
-
#{create_constraints(model).join("\n") if ::DeclareSchema.default_generate_foreign_keys}
|
272
|
-
EOS
|
296
|
+
[up * "\n\n", down * "\n\n"]
|
273
297
|
end
|
274
298
|
|
275
299
|
def create_table_options(model, disable_auto_increment)
|
276
300
|
primary_key = model._defined_primary_key
|
277
301
|
if primary_key.blank? || disable_auto_increment
|
278
|
-
|
302
|
+
{ id: false }
|
279
303
|
elsif primary_key == "id"
|
280
|
-
|
304
|
+
{ id: :bigint }
|
281
305
|
else
|
282
|
-
|
306
|
+
{ primary_key: primary_key.to_sym }
|
283
307
|
end
|
284
308
|
end
|
285
309
|
|
@@ -294,18 +318,18 @@ module Generators
|
|
294
318
|
end
|
295
319
|
end
|
296
320
|
|
321
|
+
# TODO: TECH-5338: optimize that index doesn't need to be dropped on undo since entire table will be dropped
|
297
322
|
def create_indexes(model)
|
298
|
-
model.index_definitions.map
|
323
|
+
model.index_definitions.map do |i|
|
324
|
+
::DeclareSchema::SchemaChange::IndexAdd.new(model.table_name, i.columns, unique: i.unique, where: i.where, name: i.name)
|
325
|
+
end
|
299
326
|
end
|
300
327
|
|
301
328
|
def create_constraints(model)
|
302
|
-
model.constraint_specs.map
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
options = field_spec.sql_options.merge(fk_field_options(field_spec.model, field_spec.name))
|
307
|
-
args = [field_spec.name.inspect] + format_options(options.compact)
|
308
|
-
format("t.%-*s %s", field_name_width, field_spec.type, args.join(', '))
|
329
|
+
model.constraint_specs.map do |fk|
|
330
|
+
::DeclareSchema::SchemaChange::ForeignKeyAdd.new(fk.child_table_name, fk.parent_table_name,
|
331
|
+
column_name: fk.foreign_key_name, name: fk.constraint_name)
|
332
|
+
end
|
309
333
|
end
|
310
334
|
|
311
335
|
def change_table(model, current_table_name)
|
@@ -332,37 +356,28 @@ module Generators
|
|
332
356
|
to_change = db_column_names & model_column_names
|
333
357
|
|
334
358
|
renames = to_rename.map do |old_name, new_name|
|
335
|
-
|
336
|
-
end
|
337
|
-
undo_renames = to_rename.map do |old_name, new_name|
|
338
|
-
"rename_column :#{new_table_name}, :#{new_name}, :#{old_name}"
|
359
|
+
::DeclareSchema::SchemaChange::ColumnRename.new(new_table_name, old_name, new_name)
|
339
360
|
end
|
340
361
|
|
341
|
-
to_add
|
362
|
+
to_add.sort_by! { |c| model.field_specs[c]&.position || 0 }
|
363
|
+
|
342
364
|
adds = to_add.map do |c|
|
343
|
-
|
365
|
+
type, options =
|
344
366
|
if (spec = model.field_specs[c])
|
345
|
-
|
346
|
-
[":#{spec.type}", *format_options(options.compact)]
|
367
|
+
[spec.type, spec.sql_options.merge(fk_field_options(model, c)).compact]
|
347
368
|
else
|
348
|
-
[
|
369
|
+
[:integer, {}]
|
349
370
|
end
|
350
|
-
|
351
|
-
end
|
352
|
-
undo_adds = to_add.map do |c|
|
353
|
-
"remove_column :#{new_table_name}, :#{c}"
|
371
|
+
::DeclareSchema::SchemaChange::ColumnAdd.new(new_table_name, c, type, options)
|
354
372
|
end
|
355
373
|
|
356
374
|
removes = to_remove.map do |c|
|
357
|
-
|
358
|
-
|
359
|
-
undo_removes = to_remove.map do |c|
|
360
|
-
add_column_back(model, current_table_name, c)
|
375
|
+
old_type, old_options = add_column_back(model, current_table_name, c)
|
376
|
+
::DeclareSchema::SchemaChange::ColumnRemove.new(new_table_name, c, old_type, old_options)
|
361
377
|
end
|
362
378
|
|
363
379
|
old_names = to_rename.invert
|
364
380
|
changes = []
|
365
|
-
undo_changes = []
|
366
381
|
to_change.each do |col_name_to_change|
|
367
382
|
orig_col_name = old_names[col_name_to_change] || col_name_to_change
|
368
383
|
column = db_columns[orig_col_name] or raise "failed to find column info for #{orig_col_name.inspect}"
|
@@ -374,36 +389,33 @@ module Generators
|
|
374
389
|
|
375
390
|
if !::DeclareSchema::Model::Column.equivalent_schema_attributes?(normalized_schema_attrs, col_attrs)
|
376
391
|
type = normalized_schema_attrs.delete(:type) or raise "no :type found in #{normalized_schema_attrs.inspect}"
|
377
|
-
|
378
|
-
|
379
|
-
|
392
|
+
old_type, old_options = change_column_back(model, current_table_name, orig_col_name)
|
393
|
+
changes << ::DeclareSchema::SchemaChange::ColumnChange.new(new_table_name, col_name_to_change,
|
394
|
+
new_type: type, new_options: normalized_schema_attrs,
|
395
|
+
old_type: old_type, old_options: old_options)
|
380
396
|
end
|
381
397
|
end
|
382
398
|
|
383
|
-
index_changes
|
384
|
-
fk_changes
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
table_options_changes
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
[(renames + adds + removes + changes)
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
fk_changes * "\n",
|
400
|
-
undo_fk_changes * "\n",
|
401
|
-
table_options_changes * "\n",
|
402
|
-
undo_table_options_changes * "\n"]
|
399
|
+
index_changes = change_indexes(model, current_table_name, to_rename)
|
400
|
+
fk_changes = if ActiveRecord::Base.connection.class.name.match?(/SQLite3Adapter/)
|
401
|
+
[]
|
402
|
+
else
|
403
|
+
change_foreign_key_constraints(model, current_table_name)
|
404
|
+
end
|
405
|
+
table_options_changes = if ActiveRecord::Base.connection.class.name.match?(/mysql/i)
|
406
|
+
change_table_options(model, current_table_name)
|
407
|
+
else
|
408
|
+
[]
|
409
|
+
end
|
410
|
+
|
411
|
+
[(renames + adds + removes + changes),
|
412
|
+
index_changes,
|
413
|
+
fk_changes,
|
414
|
+
table_options_changes]
|
403
415
|
end
|
404
416
|
|
405
|
-
def change_indexes(model, old_table_name,
|
406
|
-
::DeclareSchema.default_generate_indexing or return [
|
417
|
+
def change_indexes(model, old_table_name, to_rename)
|
418
|
+
::DeclareSchema.default_generate_indexing or return []
|
407
419
|
|
408
420
|
new_table_name = model.table_name
|
409
421
|
existing_indexes = ::DeclareSchema::Model::IndexDefinition.for_model(model, old_table_name)
|
@@ -415,69 +427,54 @@ module Generators
|
|
415
427
|
end
|
416
428
|
end || i
|
417
429
|
end
|
418
|
-
|
419
|
-
|
420
|
-
|
430
|
+
existing_primary_keys, existing_indexes_without_primary_key = existing_indexes.partition { |i| i.primary_key? }
|
431
|
+
defined_primary_keys, model_indexes_without_primary_key = model_indexes.partition { |i| i.primary_key? }
|
432
|
+
existing_primary_keys.size <= 1 or raise "too many existing primary keys! #{existing_primary_keys.inspect}"
|
433
|
+
defined_primary_keys.size <= 1 or raise "too many defined primary keys! #{defined_primary_keys.inspect}"
|
434
|
+
existing_primary_key = existing_primary_keys.first
|
435
|
+
defined_primary_key = defined_primary_keys.first
|
436
|
+
|
437
|
+
existing_primary_key_columns = (existing_primary_key&.columns || []).map { |col_name| to_rename[col_name] || col_name }
|
438
|
+
|
439
|
+
if !ActiveRecord::Base.connection.class.name.match?(/SQLite3Adapter/)
|
440
|
+
change_primary_key =
|
441
|
+
if (existing_primary_key || defined_primary_key) &&
|
442
|
+
existing_primary_key_columns != defined_primary_key&.columns
|
443
|
+
::DeclareSchema::SchemaChange::PrimaryKeyChange.new(new_table_name, existing_primary_key_columns, defined_primary_key&.columns)
|
444
|
+
end
|
421
445
|
end
|
422
|
-
model_has_primary_key = model_indexes.any? { |i| i.name == ::DeclareSchema::Model::IndexDefinition::PRIMARY_KEY_NAME }
|
423
446
|
|
424
|
-
|
425
|
-
|
426
|
-
undo_add_indexes << drop_index(old_table_name, i.name) unless i.name == ::DeclareSchema::Model::IndexDefinition::PRIMARY_KEY_NAME
|
427
|
-
i.to_add_statement(new_table_name, existing_has_primary_key)
|
447
|
+
drop_indexes = (existing_indexes_without_primary_key - model_indexes_without_primary_key).map do |i|
|
448
|
+
::DeclareSchema::SchemaChange::IndexRemove.new(new_table_name, i.columns, unique: i.unique, where: i.where, name: i.name)
|
428
449
|
end
|
429
|
-
undo_drop_indexes = []
|
430
|
-
drop_indexes = (existing_indexes - model_indexes).map do |i|
|
431
|
-
undo_drop_indexes << i.to_add_statement(old_table_name, model_has_primary_key)
|
432
|
-
drop_index(new_table_name, i.name) unless i.name == ::DeclareSchema::Model::IndexDefinition::PRIMARY_KEY_NAME
|
433
|
-
end.compact
|
434
450
|
|
435
|
-
|
436
|
-
|
437
|
-
|
451
|
+
add_indexes = (model_indexes_without_primary_key - existing_indexes_without_primary_key).map do |i|
|
452
|
+
::DeclareSchema::SchemaChange::IndexAdd.new(new_table_name, i.columns, unique: i.unique, where: i.where, name: i.name)
|
453
|
+
end
|
438
454
|
|
439
|
-
|
440
|
-
|
441
|
-
# for why the rescue exists
|
442
|
-
"remove_index :#{table}, name: :#{name} rescue ActiveRecord::StatementInvalid"
|
455
|
+
# the order is important here - adding a :unique, for instance needs to remove then add
|
456
|
+
[Array(change_primary_key) + drop_indexes + add_indexes]
|
443
457
|
end
|
444
458
|
|
445
459
|
def change_foreign_key_constraints(model, old_table_name)
|
446
460
|
ActiveRecord::Base.connection.class.name.match?(/SQLite3Adapter/) and raise ArgumentError, 'SQLite does not support foreign keys'
|
447
|
-
::DeclareSchema.default_generate_foreign_keys or return [
|
461
|
+
::DeclareSchema.default_generate_foreign_keys or return []
|
448
462
|
|
449
|
-
new_table_name = model.table_name
|
450
463
|
existing_fks = ::DeclareSchema::Model::ForeignKeyDefinition.for_model(model, old_table_name)
|
451
464
|
model_fks = model.constraint_specs
|
452
465
|
|
453
|
-
undo_add_fks = []
|
454
|
-
add_fks = (model_fks - existing_fks).map do |fk|
|
455
|
-
# next if fk.parent.constantize.abstract_class || fk.parent == fk.model.class_name
|
456
|
-
undo_add_fks << remove_foreign_key(old_table_name, fk.constraint_name)
|
457
|
-
fk.to_add_statement
|
458
|
-
end
|
459
|
-
|
460
|
-
undo_drop_fks = []
|
461
466
|
drop_fks = (existing_fks - model_fks).map do |fk|
|
462
|
-
|
463
|
-
|
467
|
+
::DeclareSchema::SchemaChange::ForeignKeyRemove.new(fk.child_table_name, fk.parent_table_name,
|
468
|
+
column_name: fk.foreign_key_name, name: fk.constraint_name)
|
464
469
|
end
|
465
470
|
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
"remove_foreign_key(#{old_table_name.inspect}, name: #{fk_name.to_s.inspect})"
|
471
|
-
end
|
472
|
-
|
473
|
-
def format_options(options)
|
474
|
-
options.map do |k, v|
|
475
|
-
if k.is_a?(Symbol)
|
476
|
-
"#{k}: #{v.inspect}"
|
477
|
-
else
|
478
|
-
"#{k.inspect} => #{v.inspect}"
|
479
|
-
end
|
471
|
+
add_fks = (model_fks - existing_fks).map do |fk|
|
472
|
+
# next if fk.parent.constantize.abstract_class || fk.parent == fk.model.class_name
|
473
|
+
::DeclareSchema::SchemaChange::ForeignKeyAdd.new(fk.child_table_name, fk.parent_table_name,
|
474
|
+
column_name: fk.foreign_key_name, name: fk.constraint_name)
|
480
475
|
end
|
476
|
+
|
477
|
+
[drop_fks + add_fks]
|
481
478
|
end
|
482
479
|
|
483
480
|
def fk_field_options(model, field_name)
|
@@ -506,11 +503,12 @@ module Generators
|
|
506
503
|
new_options_definition = ::DeclareSchema::Model::TableOptionsDefinition.new(model.table_name, table_options_for_model(model))
|
507
504
|
|
508
505
|
if old_options_definition.equivalent?(new_options_definition)
|
509
|
-
[
|
506
|
+
[]
|
510
507
|
else
|
511
508
|
[
|
512
|
-
|
513
|
-
|
509
|
+
::DeclareSchema::SchemaChange::TableChange.new(current_table_name,
|
510
|
+
old_options_definition.settings,
|
511
|
+
new_options_definition.settings)
|
514
512
|
]
|
515
513
|
end
|
516
514
|
end
|
@@ -528,7 +526,7 @@ module Generators
|
|
528
526
|
col_spec = ::DeclareSchema::Model::Column.new(model, current_table_name, column)
|
529
527
|
schema_attributes = col_spec.schema_attributes
|
530
528
|
type = schema_attributes.delete(:type) or raise "no :type found in #{schema_attributes.inspect}"
|
531
|
-
[
|
529
|
+
[type, schema_attributes]
|
532
530
|
end
|
533
531
|
end
|
534
532
|
|
@@ -538,7 +536,7 @@ module Generators
|
|
538
536
|
col_spec = ::DeclareSchema::Model::Column.new(model, current_table_name, column)
|
539
537
|
schema_attributes = col_spec.schema_attributes
|
540
538
|
type = schema_attributes.delete(:type) or raise "no :type found in #{schema_attributes.inspect}"
|
541
|
-
[
|
539
|
+
[type, schema_attributes]
|
542
540
|
end
|
543
541
|
end
|
544
542
|
|