declare_schema 0.6.2 → 0.8.0.pre.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 +35 -0
 - data/Gemfile.lock +55 -53
 - data/lib/declare_schema/field_declaration_dsl.rb +3 -4
 - data/lib/declare_schema/model.rb +1 -2
 - data/lib/declare_schema/model/column.rb +158 -0
 - data/lib/declare_schema/model/field_spec.rb +59 -144
 - data/lib/declare_schema/model/foreign_key_definition.rb +36 -25
 - data/lib/declare_schema/version.rb +1 -1
 - data/lib/generators/declare_schema/migration/migration_generator.rb +1 -1
 - data/lib/generators/declare_schema/migration/migrator.rb +113 -135
 - data/spec/lib/declare_schema/field_declaration_dsl_spec.rb +1 -1
 - data/spec/lib/declare_schema/field_spec_spec.rb +142 -38
 - data/spec/lib/declare_schema/migration_generator_spec.rb +73 -69
 - data/spec/lib/declare_schema/model/column_spec.rb +122 -0
 - data/spec/lib/declare_schema/model/foreign_key_definition_spec.rb +93 -0
 - data/spec/lib/generators/declare_schema/migration/migrator_spec.rb +2 -11
 - metadata +8 -5
 
| 
         @@ -5,21 +5,21 @@ module DeclareSchema 
     | 
|
| 
       5 
5 
     | 
    
         
             
                class ForeignKeyDefinition
         
     | 
| 
       6 
6 
     | 
    
         
             
                  include Comparable
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
     | 
    
         
            -
                  attr_reader :constraint_name, :model, :foreign_key, :options, :on_delete_cascade
         
     | 
| 
      
 8 
     | 
    
         
            +
                  attr_reader :constraint_name, :model, :foreign_key, :foreign_key_name, :options, :on_delete_cascade
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
       10 
10 
     | 
    
         
             
                  def initialize(model, foreign_key, options = {})
         
     | 
| 
       11 
11 
     | 
    
         
             
                    @model = model
         
     | 
| 
       12 
     | 
    
         
            -
                    @foreign_key = foreign_key.presence
         
     | 
| 
      
 12 
     | 
    
         
            +
                    @foreign_key = foreign_key.to_s.presence
         
     | 
| 
       13 
13 
     | 
    
         
             
                    @options = options
         
     | 
| 
       14 
14 
     | 
    
         | 
| 
       15 
15 
     | 
    
         
             
                    @child_table = model.table_name # unless a table rename, which would happen when a class is renamed??
         
     | 
| 
       16 
     | 
    
         
            -
                    @parent_table_name = options[:parent_table]
         
     | 
| 
       17 
     | 
    
         
            -
                    @foreign_key_name = options[:foreign_key] ||  
     | 
| 
       18 
     | 
    
         
            -
                    @index_name = options[:index_name] || model.connection.index_name(model.table_name, column:  
     | 
| 
       19 
     | 
    
         
            -
                    @constraint_name = options[:constraint_name] || @index_name || ''
         
     | 
| 
       20 
     | 
    
         
            -
                    @on_delete_cascade = options[:dependent] == :delete
         
     | 
| 
      
 16 
     | 
    
         
            +
                    @parent_table_name = options[:parent_table]&.to_s
         
     | 
| 
      
 17 
     | 
    
         
            +
                    @foreign_key_name = options[:foreign_key]&.to_s || @foreign_key
         
     | 
| 
      
 18 
     | 
    
         
            +
                    @index_name = options[:index_name]&.to_s || model.connection.index_name(model.table_name, column: @foreign_key_name)
         
     | 
| 
       21 
19 
     | 
    
         | 
| 
       22 
20 
     | 
    
         
             
                    # Empty constraint lets mysql generate the name
         
     | 
| 
      
 21 
     | 
    
         
            +
                    @constraint_name = options[:constraint_name]&.to_s || @index_name&.to_s || ''
         
     | 
| 
      
 22 
     | 
    
         
            +
                    @on_delete_cascade = options[:dependent] == :delete
         
     | 
| 
       23 
23 
     | 
    
         
             
                  end
         
     | 
| 
       24 
24 
     | 
    
         | 
| 
       25 
25 
     | 
    
         
             
                  class << self
         
     | 
| 
         @@ -28,11 +28,12 @@ module DeclareSchema 
     | 
|
| 
       28 
28 
     | 
    
         
             
                      constraints = show_create_table.split("\n").map { |line| line.strip if line['CONSTRAINT'] }.compact
         
     | 
| 
       29 
29 
     | 
    
         | 
| 
       30 
30 
     | 
    
         
             
                      constraints.map do |fkc|
         
     | 
| 
       31 
     | 
    
         
            -
                        options = {}
         
     | 
| 
       32 
31 
     | 
    
         
             
                        name, foreign_key, parent_table = fkc.match(/CONSTRAINT `([^`]*)` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)`/).captures
         
     | 
| 
       33 
     | 
    
         
            -
                        options 
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
      
 32 
     | 
    
         
            +
                        options = {
         
     | 
| 
      
 33 
     | 
    
         
            +
                          constraint_name: name,
         
     | 
| 
      
 34 
     | 
    
         
            +
                          parent_table:    parent_table,
         
     | 
| 
      
 35 
     | 
    
         
            +
                          foreign_key:     foreign_key
         
     | 
| 
      
 36 
     | 
    
         
            +
                        }
         
     | 
| 
       36 
37 
     | 
    
         
             
                        options[:dependent] = :delete if fkc['ON DELETE CASCADE']
         
     | 
| 
       37 
38 
     | 
    
         | 
| 
       38 
39 
     | 
    
         
             
                        new(model, foreign_key, options)
         
     | 
| 
         @@ -40,21 +41,37 @@ module DeclareSchema 
     | 
|
| 
       40 
41 
     | 
    
         
             
                    end
         
     | 
| 
       41 
42 
     | 
    
         
             
                  end
         
     | 
| 
       42 
43 
     | 
    
         | 
| 
      
 44 
     | 
    
         
            +
                  # returns the parent class as a Class object
         
     | 
| 
      
 45 
     | 
    
         
            +
                  # or nil if no :class_name option given
         
     | 
| 
      
 46 
     | 
    
         
            +
                  def parent_class
         
     | 
| 
      
 47 
     | 
    
         
            +
                    if (class_name = options[:class_name])
         
     | 
| 
      
 48 
     | 
    
         
            +
                      if class_name.is_a?(Class)
         
     | 
| 
      
 49 
     | 
    
         
            +
                        class_name
         
     | 
| 
      
 50 
     | 
    
         
            +
                      else
         
     | 
| 
      
 51 
     | 
    
         
            +
                        class_name.to_s.constantize
         
     | 
| 
      
 52 
     | 
    
         
            +
                      end
         
     | 
| 
      
 53 
     | 
    
         
            +
                    end
         
     | 
| 
      
 54 
     | 
    
         
            +
                  end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
       43 
56 
     | 
    
         
             
                  def parent_table_name
         
     | 
| 
       44 
57 
     | 
    
         
             
                    @parent_table_name ||=
         
     | 
| 
       45 
     | 
    
         
            -
                       
     | 
| 
       46 
     | 
    
         
            -
                         
     | 
| 
       47 
     | 
    
         
            -
                        klass.try(:table_name)
         
     | 
| 
       48 
     | 
    
         
            -
                      end || foreign_key.sub(/_id\z/, '').camelize.constantize.table_name
         
     | 
| 
      
 58 
     | 
    
         
            +
                      parent_class&.try(:table_name) ||
         
     | 
| 
      
 59 
     | 
    
         
            +
                        foreign_key.sub(/_id\z/, '').camelize.constantize.table_name
         
     | 
| 
       49 
60 
     | 
    
         
             
                  end
         
     | 
| 
       50 
61 
     | 
    
         | 
| 
       51 
     | 
    
         
            -
                   
     | 
| 
      
 62 
     | 
    
         
            +
                  def to_add_statement
         
     | 
| 
      
 63 
     | 
    
         
            +
                    "add_foreign_key(#{@child_table.inspect}, #{parent_table_name.inspect}, " +
         
     | 
| 
      
 64 
     | 
    
         
            +
                      "column: #{@foreign_key_name.inspect}, name: #{@constraint_name.inspect})"
         
     | 
| 
      
 65 
     | 
    
         
            +
                  end
         
     | 
| 
       52 
66 
     | 
    
         | 
| 
       53 
     | 
    
         
            -
                  def  
     | 
| 
       54 
     | 
    
         
            -
                     
     | 
| 
       55 
     | 
    
         
            -
                    "execute #{statement.inspect}"
         
     | 
| 
      
 67 
     | 
    
         
            +
                  def <=>(rhs)
         
     | 
| 
      
 68 
     | 
    
         
            +
                    key <=> rhs.send(:key)
         
     | 
| 
       56 
69 
     | 
    
         
             
                  end
         
     | 
| 
       57 
70 
     | 
    
         | 
| 
      
 71 
     | 
    
         
            +
                  alias eql? ==
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                  private
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
       58 
75 
     | 
    
         
             
                  def key
         
     | 
| 
       59 
76 
     | 
    
         
             
                    @key ||= [@child_table, parent_table_name, @foreign_key_name, @on_delete_cascade].map(&:to_s)
         
     | 
| 
       60 
77 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -62,12 +79,6 @@ module DeclareSchema 
     | 
|
| 
       62 
79 
     | 
    
         
             
                  def hash
         
     | 
| 
       63 
80 
     | 
    
         
             
                    key.hash
         
     | 
| 
       64 
81 
     | 
    
         
             
                  end
         
     | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
       66 
     | 
    
         
            -
                  def <=>(rhs)
         
     | 
| 
       67 
     | 
    
         
            -
                    key <=> rhs.key
         
     | 
| 
       68 
     | 
    
         
            -
                  end
         
     | 
| 
       69 
     | 
    
         
            -
             
     | 
| 
       70 
     | 
    
         
            -
                  alias eql? ==
         
     | 
| 
       71 
82 
     | 
    
         
             
                end
         
     | 
| 
       72 
83 
     | 
    
         
             
              end
         
     | 
| 
       73 
84 
     | 
    
         
             
            end
         
     | 
| 
         @@ -1,6 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            require 'active_record'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'active_record/connection_adapters/abstract_adapter'
         
     | 
| 
       4 
5 
     | 
    
         | 
| 
       5 
6 
     | 
    
         
             
            module Generators
         
     | 
| 
       6 
7 
     | 
    
         
             
              module DeclareSchema
         
     | 
| 
         @@ -116,20 +117,6 @@ module Generators 
     | 
|
| 
       116 
117 
     | 
    
         
             
                        ActiveRecord::Base.connection
         
     | 
| 
       117 
118 
     | 
    
         
             
                      end
         
     | 
| 
       118 
119 
     | 
    
         | 
| 
       119 
     | 
    
         
            -
                      def fix_native_types(types)
         
     | 
| 
       120 
     | 
    
         
            -
                        case connection.class.name
         
     | 
| 
       121 
     | 
    
         
            -
                        when /mysql/i
         
     | 
| 
       122 
     | 
    
         
            -
                          types[:integer][:limit] ||= 11
         
     | 
| 
       123 
     | 
    
         
            -
                          types[:text][:limit]    ||= 0xffff
         
     | 
| 
       124 
     | 
    
         
            -
                          types[:binary][:limit]  ||= 0xffff
         
     | 
| 
       125 
     | 
    
         
            -
                        end
         
     | 
| 
       126 
     | 
    
         
            -
                        types
         
     | 
| 
       127 
     | 
    
         
            -
                      end
         
     | 
| 
       128 
     | 
    
         
            -
             
     | 
| 
       129 
     | 
    
         
            -
                      def native_types
         
     | 
| 
       130 
     | 
    
         
            -
                        @native_types ||= fix_native_types(connection.native_database_types)
         
     | 
| 
       131 
     | 
    
         
            -
                      end
         
     | 
| 
       132 
     | 
    
         
            -
             
     | 
| 
       133 
120 
     | 
    
         
             
                      def before_generating_migration(&block)
         
     | 
| 
       134 
121 
     | 
    
         
             
                        block or raise ArgumentError, 'A block is required when setting the before_generating_migration callback'
         
     | 
| 
       135 
122 
     | 
    
         
             
                        @before_generating_migration_callback = block
         
     | 
| 
         @@ -299,7 +286,7 @@ module Generators 
     | 
|
| 
       299 
286 
     | 
    
         
             
                        "drop_table :#{t}"
         
     | 
| 
       300 
287 
     | 
    
         
             
                      end * "\n"
         
     | 
| 
       301 
288 
     | 
    
         
             
                      undo_drops = to_drop.map do |t|
         
     | 
| 
       302 
     | 
    
         
            -
                         
     | 
| 
      
 289 
     | 
    
         
            +
                        add_table_back(t)
         
     | 
| 
       303 
290 
     | 
    
         
             
                      end * "\n\n"
         
     | 
| 
       304 
291 
     | 
    
         | 
| 
       305 
292 
     | 
    
         
             
                      creates = to_create.map do |t|
         
     | 
| 
         @@ -341,11 +328,11 @@ module Generators 
     | 
|
| 
       341 
328 
     | 
    
         
             
                    end
         
     | 
| 
       342 
329 
     | 
    
         | 
| 
       343 
330 
     | 
    
         
             
                    def create_table(model)
         
     | 
| 
       344 
     | 
    
         
            -
                      longest_field_name       = model.field_specs.values.map { |f| f. 
     | 
| 
      
 331 
     | 
    
         
            +
                      longest_field_name       = model.field_specs.values.map { |f| f.type.to_s.length }.max
         
     | 
| 
       345 
332 
     | 
    
         
             
                      disable_auto_increment   = model.respond_to?(:disable_auto_increment) && model.disable_auto_increment
         
     | 
| 
       346 
333 
     | 
    
         
             
                      table_options_definition = ::DeclareSchema::Model::TableOptionsDefinition.new(model.table_name, table_options_for_model(model))
         
     | 
| 
       347 
334 
     | 
    
         
             
                      field_definitions        = [
         
     | 
| 
       348 
     | 
    
         
            -
                         
     | 
| 
      
 335 
     | 
    
         
            +
                        ("t.integer :id, limit: 8, auto_increment: false, primary_key: true" if disable_auto_increment),
         
     | 
| 
       349 
336 
     | 
    
         
             
                        *(model.field_specs.values.sort_by(&:position).map { |f| create_field(f, longest_field_name) })
         
     | 
| 
       350 
337 
     | 
    
         
             
                      ].compact
         
     | 
| 
       351 
338 
     | 
    
         | 
| 
         @@ -386,13 +373,13 @@ module Generators 
     | 
|
| 
       386 
373 
     | 
    
         
             
                    end
         
     | 
| 
       387 
374 
     | 
    
         | 
| 
       388 
375 
     | 
    
         
             
                    def create_constraints(model)
         
     | 
| 
       389 
     | 
    
         
            -
                      model.constraint_specs.map { |fk| fk.to_add_statement 
     | 
| 
      
 376 
     | 
    
         
            +
                      model.constraint_specs.map { |fk| fk.to_add_statement }
         
     | 
| 
       390 
377 
     | 
    
         
             
                    end
         
     | 
| 
       391 
378 
     | 
    
         | 
| 
       392 
379 
     | 
    
         
             
                    def create_field(field_spec, field_name_width)
         
     | 
| 
       393 
     | 
    
         
            -
                      options = fk_field_options(field_spec.model, field_spec.name) 
     | 
| 
       394 
     | 
    
         
            -
                      args = [field_spec.name.inspect] + format_options(options 
     | 
| 
       395 
     | 
    
         
            -
                      format("t.%-*s %s", field_name_width, field_spec. 
     | 
| 
      
 380 
     | 
    
         
            +
                      options = field_spec.sql_options.merge(fk_field_options(field_spec.model, field_spec.name))
         
     | 
| 
      
 381 
     | 
    
         
            +
                      args = [field_spec.name.inspect] + format_options(options.compact)
         
     | 
| 
      
 382 
     | 
    
         
            +
                      format("t.%-*s %s", field_name_width, field_spec.type, args.join(', '))
         
     | 
| 
       396 
383 
     | 
    
         
             
                    end
         
     | 
| 
       397 
384 
     | 
    
         | 
| 
       398 
385 
     | 
    
         
             
                    def change_table(model, current_table_name)
         
     | 
| 
         @@ -429,8 +416,8 @@ module Generators 
     | 
|
| 
       429 
416 
     | 
    
         
             
                      adds = to_add.map do |c|
         
     | 
| 
       430 
417 
     | 
    
         
             
                        args =
         
     | 
| 
       431 
418 
     | 
    
         
             
                          if (spec = model.field_specs[c])
         
     | 
| 
       432 
     | 
    
         
            -
                            options = fk_field_options(model, c) 
     | 
| 
       433 
     | 
    
         
            -
                            [":#{spec. 
     | 
| 
      
 419 
     | 
    
         
            +
                            options = spec.sql_options.merge(fk_field_options(model, c))
         
     | 
| 
      
 420 
     | 
    
         
            +
                            [":#{spec.type}", *format_options(options.compact)]
         
     | 
| 
       434 
421 
     | 
    
         
             
                          else
         
     | 
| 
       435 
422 
     | 
    
         
             
                            [":integer"]
         
     | 
| 
       436 
423 
     | 
    
         
             
                          end
         
     | 
| 
         @@ -444,34 +431,28 @@ module Generators 
     | 
|
| 
       444 
431 
     | 
    
         
             
                        "remove_column :#{new_table_name}, :#{c}"
         
     | 
| 
       445 
432 
     | 
    
         
             
                      end
         
     | 
| 
       446 
433 
     | 
    
         
             
                      undo_removes = to_remove.map do |c|
         
     | 
| 
       447 
     | 
    
         
            -
                         
     | 
| 
      
 434 
     | 
    
         
            +
                        add_column_back(model, current_table_name, c)
         
     | 
| 
       448 
435 
     | 
    
         
             
                      end
         
     | 
| 
       449 
436 
     | 
    
         | 
| 
       450 
437 
     | 
    
         
             
                      old_names = to_rename.invert
         
     | 
| 
       451 
438 
     | 
    
         
             
                      changes = []
         
     | 
| 
       452 
439 
     | 
    
         
             
                      undo_changes = []
         
     | 
| 
       453 
     | 
    
         
            -
                      to_change.each do | 
     | 
| 
       454 
     | 
    
         
            -
                         
     | 
| 
       455 
     | 
    
         
            -
                         
     | 
| 
       456 
     | 
    
         
            -
                        spec 
     | 
| 
       457 
     | 
    
         
            -
                         
     | 
| 
       458 
     | 
    
         
            -
             
     | 
| 
       459 
     | 
    
         
            -
             
     | 
| 
       460 
     | 
    
         
            -
             
     | 
| 
       461 
     | 
    
         
            -
             
     | 
| 
       462 
     | 
    
         
            -
             
     | 
| 
       463 
     | 
    
         
            -
                           
     | 
| 
       464 
     | 
    
         
            -
                           
     | 
| 
       465 
     | 
    
         
            -
             
     | 
| 
       466 
     | 
    
         
            -
                           
     | 
| 
       467 
     | 
    
         
            -
                          change_spec[:collation]     = spec.collation     unless spec.collation.nil?
         
     | 
| 
       468 
     | 
    
         
            -
             
     | 
| 
       469 
     | 
    
         
            -
                          changes << "change_column :#{new_table_name}, :#{c}, " +
         
     | 
| 
       470 
     | 
    
         
            -
                                     ([":#{spec.sql_type}"] + format_options(change_spec, spec.sql_type, changing: true)).join(", ")
         
     | 
| 
       471 
     | 
    
         
            -
                          back = change_column_back(current_table_name, col_name)
         
     | 
| 
       472 
     | 
    
         
            -
                          undo_changes << back unless back.blank?
         
     | 
| 
      
 440 
     | 
    
         
            +
                      to_change.each do |col_name_to_change|
         
     | 
| 
      
 441 
     | 
    
         
            +
                        orig_col_name      = old_names[col_name_to_change] || col_name_to_change
         
     | 
| 
      
 442 
     | 
    
         
            +
                        column             = db_columns[orig_col_name] or raise "failed to find column info for #{orig_col_name.inspect}"
         
     | 
| 
      
 443 
     | 
    
         
            +
                        spec               = model.field_specs[col_name_to_change] or raise "failed to find field spec for #{col_name_to_change.inspect}"
         
     | 
| 
      
 444 
     | 
    
         
            +
                        spec_attrs         = spec.schema_attributes(column)
         
     | 
| 
      
 445 
     | 
    
         
            +
                        column_declaration = ::DeclareSchema::Model::Column.new(model, current_table_name, column)
         
     | 
| 
      
 446 
     | 
    
         
            +
                        col_attrs          = column_declaration.schema_attributes
         
     | 
| 
      
 447 
     | 
    
         
            +
                        normalized_schema_attrs = spec_attrs.merge(fk_field_options(model, col_name_to_change))
         
     | 
| 
      
 448 
     | 
    
         
            +
             
     | 
| 
      
 449 
     | 
    
         
            +
                        if !::DeclareSchema::Model::Column.equivalent_schema_attributes?(normalized_schema_attrs, col_attrs)
         
     | 
| 
      
 450 
     | 
    
         
            +
                          type = normalized_schema_attrs.delete(:type) or raise "no :type found in #{normalized_schema_attrs.inspect}"
         
     | 
| 
      
 451 
     | 
    
         
            +
                          changes << ["change_column #{new_table_name.to_sym.inspect}", col_name_to_change.to_sym.inspect,
         
     | 
| 
      
 452 
     | 
    
         
            +
                                      type.to_sym.inspect, *format_options(normalized_schema_attrs)].join(", ")
         
     | 
| 
      
 453 
     | 
    
         
            +
                          undo_changes << change_column_back(model, current_table_name, orig_col_name)
         
     | 
| 
       473 
454 
     | 
    
         
             
                        end
         
     | 
| 
       474 
     | 
    
         
            -
                      end 
     | 
| 
      
 455 
     | 
    
         
            +
                      end
         
     | 
| 
       475 
456 
     | 
    
         | 
| 
       476 
457 
     | 
    
         
             
                      index_changes, undo_index_changes = change_indexes(model, current_table_name, to_remove)
         
     | 
| 
       477 
458 
     | 
    
         
             
                      fk_changes, undo_fk_changes = if ActiveRecord::Base.connection.class.name.match?(/SQLite3Adapter/)
         
     | 
| 
         @@ -485,26 +466,26 @@ module Generators 
     | 
|
| 
       485 
466 
     | 
    
         
             
                                                                            [[], []]
         
     | 
| 
       486 
467 
     | 
    
         
             
                                                                          end
         
     | 
| 
       487 
468 
     | 
    
         | 
| 
       488 
     | 
    
         
            -
                      [(renames + adds + removes + changes) 
     | 
| 
      
 469 
     | 
    
         
            +
                      [(renames + adds + removes + changes)                     * "\n",
         
     | 
| 
       489 
470 
     | 
    
         
             
                       (undo_renames + undo_adds + undo_removes + undo_changes) * "\n",
         
     | 
| 
       490 
     | 
    
         
            -
                       index_changes 
     | 
| 
       491 
     | 
    
         
            -
                       undo_index_changes 
     | 
| 
       492 
     | 
    
         
            -
                       fk_changes 
     | 
| 
       493 
     | 
    
         
            -
                       undo_fk_changes 
     | 
| 
       494 
     | 
    
         
            -
                       table_options_changes 
     | 
| 
       495 
     | 
    
         
            -
                       undo_table_options_changes 
     | 
| 
      
 471 
     | 
    
         
            +
                       index_changes                                            * "\n",
         
     | 
| 
      
 472 
     | 
    
         
            +
                       undo_index_changes                                       * "\n",
         
     | 
| 
      
 473 
     | 
    
         
            +
                       fk_changes                                               * "\n",
         
     | 
| 
      
 474 
     | 
    
         
            +
                       undo_fk_changes                                          * "\n",
         
     | 
| 
      
 475 
     | 
    
         
            +
                       table_options_changes                                    * "\n",
         
     | 
| 
      
 476 
     | 
    
         
            +
                       undo_table_options_changes                               * "\n"]
         
     | 
| 
       496 
477 
     | 
    
         
             
                    end
         
     | 
| 
       497 
478 
     | 
    
         | 
| 
       498 
479 
     | 
    
         
             
                    def change_indexes(model, old_table_name, to_remove)
         
     | 
| 
       499 
     | 
    
         
            -
                      return [[], []] 
     | 
| 
      
 480 
     | 
    
         
            +
                      Migrator.disable_constraints and return [[], []]
         
     | 
| 
       500 
481 
     | 
    
         | 
| 
       501 
482 
     | 
    
         
             
                      new_table_name = model.table_name
         
     | 
| 
       502 
483 
     | 
    
         
             
                      existing_indexes = ::DeclareSchema::Model::IndexDefinition.for_model(model, old_table_name)
         
     | 
| 
       503 
484 
     | 
    
         
             
                      model_indexes_with_equivalents = model.index_definitions_with_primary_key
         
     | 
| 
       504 
485 
     | 
    
         
             
                      model_indexes = model_indexes_with_equivalents.map do |i|
         
     | 
| 
       505 
486 
     | 
    
         
             
                        if i.explicit_name.nil?
         
     | 
| 
       506 
     | 
    
         
            -
                          if  
     | 
| 
       507 
     | 
    
         
            -
                            i.with_name( 
     | 
| 
      
 487 
     | 
    
         
            +
                          if (existing = existing_indexes.find { |e| i != e && e.equivalent?(i) })
         
     | 
| 
      
 488 
     | 
    
         
            +
                            i.with_name(existing.name)
         
     | 
| 
       508 
489 
     | 
    
         
             
                          end
         
     | 
| 
       509 
490 
     | 
    
         
             
                        end || i
         
     | 
| 
       510 
491 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -514,15 +495,13 @@ module Generators 
     | 
|
| 
       514 
495 
     | 
    
         
             
                      end
         
     | 
| 
       515 
496 
     | 
    
         
             
                      model_has_primary_key    = model_indexes.any?    { |i| i.name == ::DeclareSchema::Model::IndexDefinition::PRIMARY_KEY_NAME }
         
     | 
| 
       516 
497 
     | 
    
         | 
| 
       517 
     | 
    
         
            -
                      add_indexes_init = model_indexes - existing_indexes
         
     | 
| 
       518 
     | 
    
         
            -
                      drop_indexes_init = existing_indexes - model_indexes
         
     | 
| 
       519 
498 
     | 
    
         
             
                      undo_add_indexes = []
         
     | 
| 
       520 
     | 
    
         
            -
                       
     | 
| 
       521 
     | 
    
         
            -
                      add_indexes = add_indexes_init.map do |i|
         
     | 
| 
      
 499 
     | 
    
         
            +
                      add_indexes = (model_indexes - existing_indexes).map do |i|
         
     | 
| 
       522 
500 
     | 
    
         
             
                        undo_add_indexes << drop_index(old_table_name, i.name) unless i.name == ::DeclareSchema::Model::IndexDefinition::PRIMARY_KEY_NAME
         
     | 
| 
       523 
501 
     | 
    
         
             
                        i.to_add_statement(new_table_name, existing_has_primary_key)
         
     | 
| 
       524 
502 
     | 
    
         
             
                      end
         
     | 
| 
       525 
     | 
    
         
            -
                       
     | 
| 
      
 503 
     | 
    
         
            +
                      undo_drop_indexes = []
         
     | 
| 
      
 504 
     | 
    
         
            +
                      drop_indexes = (existing_indexes - model_indexes).map do |i|
         
     | 
| 
       526 
505 
     | 
    
         
             
                        undo_drop_indexes << i.to_add_statement(old_table_name, model_has_primary_key)
         
     | 
| 
       527 
506 
     | 
    
         
             
                        drop_index(new_table_name, i.name) unless i.name == ::DeclareSchema::Model::IndexDefinition::PRIMARY_KEY_NAME
         
     | 
| 
       528 
507 
     | 
    
         
             
                      end.compact
         
     | 
| 
         @@ -538,51 +517,41 @@ module Generators 
     | 
|
| 
       538 
517 
     | 
    
         
             
                    end
         
     | 
| 
       539 
518 
     | 
    
         | 
| 
       540 
519 
     | 
    
         
             
                    def change_foreign_key_constraints(model, old_table_name)
         
     | 
| 
       541 
     | 
    
         
            -
                      ActiveRecord::Base.connection.class.name.match?(/SQLite3Adapter/) and raise 'SQLite does not support foreign keys'
         
     | 
| 
       542 
     | 
    
         
            -
                      return [[], []] 
     | 
| 
      
 520 
     | 
    
         
            +
                      ActiveRecord::Base.connection.class.name.match?(/SQLite3Adapter/) and raise ArgumentError, 'SQLite does not support foreign keys'
         
     | 
| 
      
 521 
     | 
    
         
            +
                      Migrator.disable_indexing and return [[], []]
         
     | 
| 
       543 
522 
     | 
    
         | 
| 
       544 
523 
     | 
    
         
             
                      new_table_name = model.table_name
         
     | 
| 
       545 
524 
     | 
    
         
             
                      existing_fks = ::DeclareSchema::Model::ForeignKeyDefinition.for_model(model, old_table_name)
         
     | 
| 
       546 
525 
     | 
    
         
             
                      model_fks = model.constraint_specs
         
     | 
| 
       547 
     | 
    
         
            -
                      add_fks = model_fks - existing_fks
         
     | 
| 
       548 
     | 
    
         
            -
                      drop_fks = existing_fks - model_fks
         
     | 
| 
       549 
     | 
    
         
            -
                      undo_add_fks = []
         
     | 
| 
       550 
     | 
    
         
            -
                      undo_drop_fks = []
         
     | 
| 
       551 
526 
     | 
    
         | 
| 
       552 
     | 
    
         
            -
                       
     | 
| 
      
 527 
     | 
    
         
            +
                      undo_add_fks = []
         
     | 
| 
      
 528 
     | 
    
         
            +
                      add_fks = (model_fks - existing_fks).map do |fk|
         
     | 
| 
       553 
529 
     | 
    
         
             
                        # next if fk.parent.constantize.abstract_class || fk.parent == fk.model.class_name
         
     | 
| 
       554 
     | 
    
         
            -
                        undo_add_fks << remove_foreign_key(old_table_name, fk. 
     | 
| 
      
 530 
     | 
    
         
            +
                        undo_add_fks << remove_foreign_key(old_table_name, fk.constraint_name)
         
     | 
| 
       555 
531 
     | 
    
         
             
                        fk.to_add_statement
         
     | 
| 
       556 
     | 
    
         
            -
                      end 
     | 
| 
      
 532 
     | 
    
         
            +
                      end
         
     | 
| 
       557 
533 
     | 
    
         | 
| 
       558 
     | 
    
         
            -
                       
     | 
| 
      
 534 
     | 
    
         
            +
                      undo_drop_fks = []
         
     | 
| 
      
 535 
     | 
    
         
            +
                      drop_fks = (existing_fks - model_fks).map do |fk|
         
     | 
| 
       559 
536 
     | 
    
         
             
                        undo_drop_fks << fk.to_add_statement
         
     | 
| 
       560 
     | 
    
         
            -
                        remove_foreign_key(new_table_name, fk. 
     | 
| 
      
 537 
     | 
    
         
            +
                        remove_foreign_key(new_table_name, fk.constraint_name)
         
     | 
| 
       561 
538 
     | 
    
         
             
                      end
         
     | 
| 
       562 
539 
     | 
    
         | 
| 
       563 
540 
     | 
    
         
             
                      [drop_fks + add_fks, undo_add_fks + undo_drop_fks]
         
     | 
| 
       564 
541 
     | 
    
         
             
                    end
         
     | 
| 
       565 
542 
     | 
    
         | 
| 
       566 
543 
     | 
    
         
             
                    def remove_foreign_key(old_table_name, fk_name)
         
     | 
| 
       567 
     | 
    
         
            -
                      "remove_foreign_key( 
     | 
| 
      
 544 
     | 
    
         
            +
                      "remove_foreign_key(#{old_table_name.inspect}, name: #{fk_name.to_s.inspect})"
         
     | 
| 
       568 
545 
     | 
    
         
             
                    end
         
     | 
| 
       569 
546 
     | 
    
         | 
| 
       570 
     | 
    
         
            -
                    def format_options(options 
     | 
| 
      
 547 
     | 
    
         
            +
                    def format_options(options)
         
     | 
| 
       571 
548 
     | 
    
         
             
                      options.map do |k, v|
         
     | 
| 
       572 
     | 
    
         
            -
                        if !changing && ((k == :limit && type == :decimal) || (k == :null && v == true))
         
     | 
| 
       573 
     | 
    
         
            -
                          next
         
     | 
| 
       574 
     | 
    
         
            -
                        end
         
     | 
| 
       575 
     | 
    
         
            -
             
     | 
| 
       576 
     | 
    
         
            -
                        if !::DeclareSchema::Model::FieldSpec.mysql_text_limits? && k == :limit && type == :text
         
     | 
| 
       577 
     | 
    
         
            -
                          next
         
     | 
| 
       578 
     | 
    
         
            -
                        end
         
     | 
| 
       579 
     | 
    
         
            -
             
     | 
| 
       580 
549 
     | 
    
         
             
                        if k.is_a?(Symbol)
         
     | 
| 
       581 
550 
     | 
    
         
             
                          "#{k}: #{v.inspect}"
         
     | 
| 
       582 
551 
     | 
    
         
             
                        else
         
     | 
| 
       583 
552 
     | 
    
         
             
                          "#{k.inspect} => #{v.inspect}"
         
     | 
| 
       584 
553 
     | 
    
         
             
                        end
         
     | 
| 
       585 
     | 
    
         
            -
                      end 
     | 
| 
      
 554 
     | 
    
         
            +
                      end
         
     | 
| 
       586 
555 
     | 
    
         
             
                    end
         
     | 
| 
       587 
556 
     | 
    
         | 
| 
       588 
557 
     | 
    
         
             
                    def fk_field_options(model, field_name)
         
     | 
| 
         @@ -620,7 +589,33 @@ module Generators 
     | 
|
| 
       620 
589 
     | 
    
         
             
                      end
         
     | 
| 
       621 
590 
     | 
    
         
             
                    end
         
     | 
| 
       622 
591 
     | 
    
         | 
| 
       623 
     | 
    
         
            -
                     
     | 
| 
      
 592 
     | 
    
         
            +
                    def with_previous_model_table_name(model, table_name)
         
     | 
| 
      
 593 
     | 
    
         
            +
                      model_table_name, model.table_name = model.table_name, table_name
         
     | 
| 
      
 594 
     | 
    
         
            +
                      yield
         
     | 
| 
      
 595 
     | 
    
         
            +
                    ensure
         
     | 
| 
      
 596 
     | 
    
         
            +
                      model.table_name = model_table_name
         
     | 
| 
      
 597 
     | 
    
         
            +
                    end
         
     | 
| 
      
 598 
     | 
    
         
            +
             
     | 
| 
      
 599 
     | 
    
         
            +
                    def add_column_back(model, current_table_name, col_name)
         
     | 
| 
      
 600 
     | 
    
         
            +
                      with_previous_model_table_name(model, current_table_name) do
         
     | 
| 
      
 601 
     | 
    
         
            +
                        column = model.columns_hash[col_name] or raise "no columns_hash entry found for #{col_name} in #{model.inspect}"
         
     | 
| 
      
 602 
     | 
    
         
            +
                        col_spec = ::DeclareSchema::Model::Column.new(model, current_table_name, column)
         
     | 
| 
      
 603 
     | 
    
         
            +
                        schema_attributes = col_spec.schema_attributes
         
     | 
| 
      
 604 
     | 
    
         
            +
                        type = schema_attributes.delete(:type) or raise "no :type found in #{schema_attributes.inspect}"
         
     | 
| 
      
 605 
     | 
    
         
            +
                        ["add_column :#{current_table_name}, :#{col_name}, #{type.inspect}", *format_options(schema_attributes)].join(', ')
         
     | 
| 
      
 606 
     | 
    
         
            +
                      end
         
     | 
| 
      
 607 
     | 
    
         
            +
                    end
         
     | 
| 
      
 608 
     | 
    
         
            +
             
     | 
| 
      
 609 
     | 
    
         
            +
                    def change_column_back(model, current_table_name, col_name)
         
     | 
| 
      
 610 
     | 
    
         
            +
                      with_previous_model_table_name(model, current_table_name) do
         
     | 
| 
      
 611 
     | 
    
         
            +
                        column = model.columns_hash[col_name] or raise "no columns_hash entry found for #{col_name} in #{model.inspect}"
         
     | 
| 
      
 612 
     | 
    
         
            +
                        col_spec = ::DeclareSchema::Model::Column.new(model, current_table_name, column)
         
     | 
| 
      
 613 
     | 
    
         
            +
                        schema_attributes = col_spec.schema_attributes
         
     | 
| 
      
 614 
     | 
    
         
            +
                        type = schema_attributes.delete(:type) or raise "no :type found in #{schema_attributes.inspect}"
         
     | 
| 
      
 615 
     | 
    
         
            +
                        ["change_column #{current_table_name.to_sym.inspect}", col_name.to_sym.inspect, type.to_sym.inspect, *format_options(schema_attributes)].join(', ')
         
     | 
| 
      
 616 
     | 
    
         
            +
                      end
         
     | 
| 
      
 617 
     | 
    
         
            +
                    end
         
     | 
| 
      
 618 
     | 
    
         
            +
             
     | 
| 
       624 
619 
     | 
    
         
             
                    def default_collation_from_charset(charset)
         
     | 
| 
       625 
620 
     | 
    
         
             
                      case charset
         
     | 
| 
       626 
621 
     | 
    
         
             
                      when "utf8"
         
     | 
| 
         @@ -630,64 +625,47 @@ module Generators 
     | 
|
| 
       630 
625 
     | 
    
         
             
                      end
         
     | 
| 
       631 
626 
     | 
    
         
             
                    end
         
     | 
| 
       632 
627 
     | 
    
         | 
| 
       633 
     | 
    
         
            -
                     
     | 
| 
       634 
     | 
    
         
            -
             
     | 
| 
       635 
     | 
    
         
            -
             
     | 
| 
       636 
     | 
    
         
            -
             
     | 
| 
       637 
     | 
    
         
            -
             
     | 
| 
       638 
     | 
    
         
            -
             
     | 
| 
       639 
     | 
    
         
            -
             
     | 
| 
       640 
     | 
    
         
            -
             
     | 
| 
       641 
     | 
    
         
            -
                       
     | 
| 
      
 628 
     | 
    
         
            +
                    SchemaDumper = case Rails::VERSION::MAJOR
         
     | 
| 
      
 629 
     | 
    
         
            +
                                   when 4
         
     | 
| 
      
 630 
     | 
    
         
            +
                                     ActiveRecord::SchemaDumper
         
     | 
| 
      
 631 
     | 
    
         
            +
                                   else
         
     | 
| 
      
 632 
     | 
    
         
            +
                                     ActiveRecord::ConnectionAdapters::SchemaDumper
         
     | 
| 
      
 633 
     | 
    
         
            +
                                   end
         
     | 
| 
      
 634 
     | 
    
         
            +
             
     | 
| 
      
 635 
     | 
    
         
            +
                    def add_table_back(table)
         
     | 
| 
      
 636 
     | 
    
         
            +
                      dumped_schema_stream = StringIO.new
         
     | 
| 
      
 637 
     | 
    
         
            +
                      SchemaDumper.send(:new, ActiveRecord::Base.connection).send(:table, table, dumped_schema_stream)
         
     | 
| 
       642 
638 
     | 
    
         | 
| 
       643 
     | 
    
         
            -
                       
     | 
| 
      
 639 
     | 
    
         
            +
                      dumped_schema = dumped_schema_stream.string.strip.gsub!("\n  ", "\n")
         
     | 
| 
       644 
640 
     | 
    
         
             
                      if connection.class.name.match?(/mysql/i)
         
     | 
| 
       645 
     | 
    
         
            -
                         
     | 
| 
       646 
     | 
    
         
            -
             
     | 
| 
       647 
     | 
    
         
            -
             
     | 
| 
       648 
     | 
    
         
            -
                        end
         
     | 
| 
       649 
     | 
    
         
            -
                        default_charset   = result[/CHARSET=(\w+)/, 1]   or raise "unable to find charset in #{result.inspect}"
         
     | 
| 
       650 
     | 
    
         
            -
                        default_collation = result[/COLLATE=(\w+)/, 1] || default_collation_from_charset(default_charset) or
         
     | 
| 
       651 
     | 
    
         
            -
                          raise "unable to find collation in #{result.inspect} or charset #{default_charset.inspect}"
         
     | 
| 
       652 
     | 
    
         
            -
                        result = result.split("\n").map do |line|
         
     | 
| 
       653 
     | 
    
         
            -
                          if line['t.text'] || line['t.string']
         
     | 
| 
       654 
     | 
    
         
            -
                            if !line['charset: ']
         
     | 
| 
       655 
     | 
    
         
            -
                              if line['collation: ']
         
     | 
| 
       656 
     | 
    
         
            -
                                line = line.sub('collation: ', "charset: #{default_charset.inspect}, collation: ")
         
     | 
| 
       657 
     | 
    
         
            -
                              else
         
     | 
| 
       658 
     | 
    
         
            -
                                line += ", charset: #{default_charset.inspect}"
         
     | 
| 
       659 
     | 
    
         
            -
                              end
         
     | 
| 
       660 
     | 
    
         
            -
                            end
         
     | 
| 
       661 
     | 
    
         
            -
                            line['collation: '] or line += ", collation: #{default_collation.inspect}"
         
     | 
| 
       662 
     | 
    
         
            -
                          end
         
     | 
| 
       663 
     | 
    
         
            -
                          line
         
     | 
| 
       664 
     | 
    
         
            -
                        end.join("\n")
         
     | 
| 
      
 641 
     | 
    
         
            +
                        fix_mysql_charset_and_collation(dumped_schema)
         
     | 
| 
      
 642 
     | 
    
         
            +
                      else
         
     | 
| 
      
 643 
     | 
    
         
            +
                        dumped_schema
         
     | 
| 
       665 
644 
     | 
    
         
             
                      end
         
     | 
| 
       666 
     | 
    
         
            -
                      result
         
     | 
| 
       667 
645 
     | 
    
         
             
                    end
         
     | 
| 
       668 
646 
     | 
    
         | 
| 
       669 
     | 
    
         
            -
                     
     | 
| 
       670 
     | 
    
         
            -
             
     | 
| 
       671 
     | 
    
         
            -
                      if  
     | 
| 
       672 
     | 
    
         
            -
                         
     | 
| 
       673 
     | 
    
         
            -
             
     | 
| 
       674 
     | 
    
         
            -
                      elsif (md = revert.match(/\s*t\.([a-z_]+)\s+"#{column}"(?:,\s+(.*?)$)?/m))
         
     | 
| 
       675 
     | 
    
         
            -
                        # Sexy migration
         
     | 
| 
       676 
     | 
    
         
            -
                        _, string_type, options = *md
         
     | 
| 
       677 
     | 
    
         
            -
                        type = ":#{string_type}"
         
     | 
| 
      
 647 
     | 
    
         
            +
                    # TODO: rewrite this method to use charset and collation variables rather than manipulating strings. -Colin
         
     | 
| 
      
 648 
     | 
    
         
            +
                    def fix_mysql_charset_and_collation(dumped_schema)
         
     | 
| 
      
 649 
     | 
    
         
            +
                      if !dumped_schema['options: ']
         
     | 
| 
      
 650 
     | 
    
         
            +
                        dumped_schema.sub!('",', "\", options: \"DEFAULT CHARSET=#{Generators::DeclareSchema::Migration::Migrator.default_charset} "+
         
     | 
| 
      
 651 
     | 
    
         
            +
                          "COLLATE=#{Generators::DeclareSchema::Migration::Migrator.default_collation}\",")
         
     | 
| 
       678 
652 
     | 
    
         
             
                      end
         
     | 
| 
       679 
     | 
    
         
            -
                       
     | 
| 
       680 
     | 
    
         
            -
                      [ 
     | 
| 
       681 
     | 
    
         
            -
             
     | 
| 
       682 
     | 
    
         
            -
             
     | 
| 
       683 
     | 
    
         
            -
             
     | 
| 
       684 
     | 
    
         
            -
             
     | 
| 
       685 
     | 
    
         
            -
             
     | 
| 
       686 
     | 
    
         
            -
             
     | 
| 
       687 
     | 
    
         
            -
             
     | 
| 
       688 
     | 
    
         
            -
             
     | 
| 
       689 
     | 
    
         
            -
             
     | 
| 
       690 
     | 
    
         
            -
             
     | 
| 
      
 653 
     | 
    
         
            +
                      default_charset   = dumped_schema[/CHARSET=(\w+)/, 1]   or raise "unable to find charset in #{dumped_schema.inspect}"
         
     | 
| 
      
 654 
     | 
    
         
            +
                      default_collation = dumped_schema[/COLLATE=(\w+)/, 1] || default_collation_from_charset(default_charset) or
         
     | 
| 
      
 655 
     | 
    
         
            +
                        raise "unable to find collation in #{dumped_schema.inspect} or charset #{default_charset.inspect}"
         
     | 
| 
      
 656 
     | 
    
         
            +
                      dumped_schema.split("\n").map do |line|
         
     | 
| 
      
 657 
     | 
    
         
            +
                        if line['t.text'] || line['t.string']
         
     | 
| 
      
 658 
     | 
    
         
            +
                          if !line['charset: ']
         
     | 
| 
      
 659 
     | 
    
         
            +
                            if line['collation: ']
         
     | 
| 
      
 660 
     | 
    
         
            +
                              line.sub!('collation: ', "charset: #{default_charset.inspect}, collation: ")
         
     | 
| 
      
 661 
     | 
    
         
            +
                            else
         
     | 
| 
      
 662 
     | 
    
         
            +
                              line << ", charset: #{default_charset.inspect}"
         
     | 
| 
      
 663 
     | 
    
         
            +
                            end
         
     | 
| 
      
 664 
     | 
    
         
            +
                          end
         
     | 
| 
      
 665 
     | 
    
         
            +
                          line['collation: '] or line << ", collation: #{default_collation.inspect}"
         
     | 
| 
      
 666 
     | 
    
         
            +
                        end
         
     | 
| 
      
 667 
     | 
    
         
            +
                        line
         
     | 
| 
      
 668 
     | 
    
         
            +
                      end.join("\n")
         
     | 
| 
       691 
669 
     | 
    
         
             
                    end
         
     | 
| 
       692 
670 
     | 
    
         
             
                  end
         
     | 
| 
       693 
671 
     | 
    
         
             
                end
         
     |