schema_plus 0.4.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +3 -1
 - data/.travis.yml +6 -9
 - data/Gemfile +0 -4
 - data/README.rdoc +168 -70
 - data/Rakefile +58 -47
 - data/gemfiles/rails-3.2/Gemfile.base +4 -0
 - data/gemfiles/rails-3.2/Gemfile.mysql +4 -0
 - data/gemfiles/rails-3.2/Gemfile.mysql2 +4 -0
 - data/gemfiles/rails-3.2/Gemfile.postgresql +4 -0
 - data/gemfiles/rails-3.2/Gemfile.sqlite3 +4 -0
 - data/lib/schema_plus.rb +2 -0
 - data/lib/schema_plus/active_record/column_options_handler.rb +73 -32
 - data/lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb +60 -31
 - data/lib/schema_plus/active_record/connection_adapters/foreign_key_definition.rb +7 -2
 - data/lib/schema_plus/active_record/connection_adapters/index_definition.rb +2 -1
 - data/lib/schema_plus/active_record/connection_adapters/mysql_adapter.rb +19 -1
 - data/lib/schema_plus/active_record/connection_adapters/postgresql_adapter.rb +68 -17
 - data/lib/schema_plus/active_record/connection_adapters/sqlite3_adapter.rb +28 -3
 - data/lib/schema_plus/active_record/connection_adapters/table_definition.rb +27 -1
 - data/lib/schema_plus/active_record/db_default.rb +19 -0
 - data/lib/schema_plus/active_record/foreign_keys.rb +40 -32
 - data/lib/schema_plus/active_record/schema_dumper.rb +7 -3
 - data/lib/schema_plus/version.rb +1 -1
 - data/runspecs +5 -8
 - data/schema_plus.gemspec +2 -5
 - data/spec/column_definition_spec.rb +18 -1
 - data/spec/column_spec.rb +39 -2
 - data/spec/connection_spec.rb +1 -1
 - data/spec/connections/mysql/connection.rb +1 -1
 - data/spec/connections/mysql2/connection.rb +1 -1
 - data/spec/connections/postgresql/connection.rb +1 -1
 - data/spec/foreign_key_definition_spec.rb +0 -4
 - data/spec/foreign_key_spec.rb +37 -13
 - data/spec/index_definition_spec.rb +54 -2
 - data/spec/index_spec.rb +59 -15
 - data/spec/migration_spec.rb +336 -85
 - data/spec/multiple_schemas_spec.rb +127 -0
 - data/spec/schema_dumper_spec.rb +65 -25
 - data/spec/schema_spec.rb +16 -18
 - data/spec/spec_helper.rb +19 -18
 - data/spec/support/matchers/reference.rb +7 -1
 - data/spec/views_spec.rb +5 -2
 - metadata +43 -54
 - data/gemfiles/Gemfile.rails-2.3 +0 -6
 - data/gemfiles/Gemfile.rails-2.3.lock +0 -65
 - data/gemfiles/Gemfile.rails-3.0 +0 -5
 - data/gemfiles/Gemfile.rails-3.0.lock +0 -113
 - data/gemfiles/Gemfile.rails-3.1 +0 -5
 - data/gemfiles/Gemfile.rails-3.1.lock +0 -123
 - data/gemfiles/Gemfile.rails-3.2 +0 -5
 - data/gemfiles/Gemfile.rails-3.2.lock +0 -121
 - data/spec/models/comment.rb +0 -2
 - data/spec/models/post.rb +0 -2
 - data/spec/models/user.rb +0 -2
 - data/spec/rails3_migration_spec.rb +0 -144
 
    
        data/lib/schema_plus.rb
    CHANGED
    
    | 
         @@ -3,6 +3,7 @@ require 'valuable' 
     | 
|
| 
       3 
3 
     | 
    
         
             
            require 'schema_plus/version'
         
     | 
| 
       4 
4 
     | 
    
         
             
            require 'schema_plus/active_record/base'
         
     | 
| 
       5 
5 
     | 
    
         
             
            require 'schema_plus/active_record/column_options_handler'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'schema_plus/active_record/db_default'
         
     | 
| 
       6 
7 
     | 
    
         
             
            require 'schema_plus/active_record/foreign_keys'
         
     | 
| 
       7 
8 
     | 
    
         
             
            require 'schema_plus/active_record/connection_adapters/table_definition'
         
     | 
| 
       8 
9 
     | 
    
         
             
            require 'schema_plus/active_record/connection_adapters/schema_statements'
         
     | 
| 
         @@ -132,6 +133,7 @@ module SchemaPlus 
     | 
|
| 
       132 
133 
     | 
    
         
             
                ::ActiveRecord::Base.send(:include, SchemaPlus::ActiveRecord::Base)
         
     | 
| 
       133 
134 
     | 
    
         
             
                ::ActiveRecord::Schema.send(:include, SchemaPlus::ActiveRecord::Schema)
         
     | 
| 
       134 
135 
     | 
    
         
             
                ::ActiveRecord::SchemaDumper.send(:include, SchemaPlus::ActiveRecord::SchemaDumper)
         
     | 
| 
      
 136 
     | 
    
         
            +
                ::ActiveRecord.const_set(:DB_DEFAULT, SchemaPlus::ActiveRecord::DB_DEFAULT)
         
     | 
| 
       135 
137 
     | 
    
         
             
              end
         
     | 
| 
       136 
138 
     | 
    
         | 
| 
       137 
139 
     | 
    
         
             
            end
         
     | 
| 
         @@ -2,48 +2,80 @@ module SchemaPlus::ActiveRecord 
     | 
|
| 
       2 
2 
     | 
    
         
             
              module ColumnOptionsHandler
         
     | 
| 
       3 
3 
     | 
    
         
             
                def schema_plus_handle_column_options(table_name, column_name, column_options, opts = {}) #:nodoc:
         
     | 
| 
       4 
4 
     | 
    
         
             
                  config = opts[:config] || SchemaPlus.config
         
     | 
| 
       5 
     | 
    
         
            -
                   
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
     | 
    
         
            -
                     
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
             
     | 
| 
      
 5 
     | 
    
         
            +
                  fk_args = get_fk_args(table_name, column_name, column_options, config)
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                  # remove existing fk and auto-generated index in case of change to existing column
         
     | 
| 
      
 8 
     | 
    
         
            +
                  if fk_args # includes :none for explicitly off
         
     | 
| 
      
 9 
     | 
    
         
            +
                    remove_foreign_key_if_exists(table_name, column_name)
         
     | 
| 
      
 10 
     | 
    
         
            +
                    remove_auto_index_if_exists(table_name, column_name)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  fk_args = nil if fk_args == :none
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  # create index if requested explicity or implicitly due to auto_index
         
     | 
| 
      
 16 
     | 
    
         
            +
                  index = column_options[:index]
         
     | 
| 
      
 17 
     | 
    
         
            +
                  if index.nil? and fk_args && config.foreign_keys.auto_index?
         
     | 
| 
      
 18 
     | 
    
         
            +
                    index = { :name => auto_index_name(table_name, column_name) }
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
                  column_index(table_name, column_name, index) if index
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  if fk_args
         
     | 
| 
      
 23 
     | 
    
         
            +
                    references = fk_args.delete(:references)
         
     | 
| 
      
 24 
     | 
    
         
            +
                    add_foreign_key(table_name, column_name, references.first, references.last, fk_args)
         
     | 
| 
       14 
25 
     | 
    
         
             
                  end
         
     | 
| 
       15 
26 
     | 
    
         
             
                end
         
     | 
| 
       16 
27 
     | 
    
         | 
| 
       17 
28 
     | 
    
         
             
                protected
         
     | 
| 
       18 
29 
     | 
    
         | 
| 
       19 
     | 
    
         
            -
                 
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
     | 
    
         
            -
                #
         
     | 
| 
       31 
     | 
    
         
            -
                def get_references(table_name, column_name, column_options = {}, config = {}) #:nodoc:
         
     | 
| 
      
 30 
     | 
    
         
            +
                def get_fk_args(table_name, column_name, column_options = {}, config = {}) #:nodoc:
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  args = nil
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  if column_options.has_key?(:foreign_key)
         
     | 
| 
      
 35 
     | 
    
         
            +
                    args = column_options[:foreign_key]
         
     | 
| 
      
 36 
     | 
    
         
            +
                    return :none unless args
         
     | 
| 
      
 37 
     | 
    
         
            +
                    args = {} if args == true
         
     | 
| 
      
 38 
     | 
    
         
            +
                    return :none if args.has_key?(:references) and not args[:references]
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
       32 
41 
     | 
    
         
             
                  if column_options.has_key?(:references)
         
     | 
| 
       33 
42 
     | 
    
         
             
                    references = column_options[:references]
         
     | 
| 
       34 
     | 
    
         
            -
                     
     | 
| 
       35 
     | 
    
         
            -
                    references
         
     | 
| 
       36 
     | 
    
         
            -
                   
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
      
 43 
     | 
    
         
            +
                    return :none unless references
         
     | 
| 
      
 44 
     | 
    
         
            +
                    args = (args || {}).reverse_merge(:references => references)
         
     | 
| 
      
 45 
     | 
    
         
            +
                  end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                  args ||= {} if config.foreign_keys.auto_create? and column_name =~ /_id$/
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                  return nil if args.nil?
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                  args[:references] ||= case column_name.to_s
         
     | 
| 
      
 52 
     | 
    
         
            +
                                        when 'parent_id'
         
     | 
| 
      
 53 
     | 
    
         
            +
                                          [table_name, :id]
         
     | 
| 
      
 54 
     | 
    
         
            +
                                        when /^(.*)_id$/
         
     | 
| 
      
 55 
     | 
    
         
            +
                                          references_table_name = ActiveRecord::Base.pluralize_table_names ? $1.to_s.pluralize : $1
         
     | 
| 
      
 56 
     | 
    
         
            +
                                          [references_table_name, :id]
         
     | 
| 
      
 57 
     | 
    
         
            +
                                        else
         
     | 
| 
      
 58 
     | 
    
         
            +
                                          references_table_name = ActiveRecord::Base.pluralize_table_names ? column_name.to_s.pluralize : column_name
         
     | 
| 
      
 59 
     | 
    
         
            +
                                        end
         
     | 
| 
      
 60 
     | 
    
         
            +
                  args[:references] = [args[:references], :id] unless args[:references].is_a? Array
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                  [:on_update, :on_delete, :deferrable].each do |shortcut|
         
     | 
| 
      
 63 
     | 
    
         
            +
                    args[shortcut] ||= column_options[shortcut] if column_options.has_key? shortcut
         
     | 
| 
       44 
64 
     | 
    
         
             
                  end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                  args[:on_update] ||= config.foreign_keys.on_update
         
     | 
| 
      
 67 
     | 
    
         
            +
                  args[:on_delete] ||= config.foreign_keys.on_delete
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                  args
         
     | 
| 
      
 70 
     | 
    
         
            +
                end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                def remove_foreign_key_if_exists(table_name, column_name) #:nodoc:
         
     | 
| 
      
 73 
     | 
    
         
            +
                  foreign_keys = ActiveRecord::Base.connection.foreign_keys(table_name.to_s) rescue [] # no fks if table_name doesn't exist
         
     | 
| 
      
 74 
     | 
    
         
            +
                  fk = foreign_keys.detect { |fk| fk.table_name == table_name.to_s && fk.column_names == Array(column_name).collect(&:to_s) }
         
     | 
| 
      
 75 
     | 
    
         
            +
                  remove_foreign_key(table_name, fk.name) if fk
         
     | 
| 
       45 
76 
     | 
    
         
             
                end
         
     | 
| 
       46 
77 
     | 
    
         | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
       47 
79 
     | 
    
         
             
                def column_index(table_name, column_name, options) #:nodoc:
         
     | 
| 
       48 
80 
     | 
    
         
             
                  options = {} if options == true
         
     | 
| 
       49 
81 
     | 
    
         
             
                  options = { :unique => true } if options == :unique
         
     | 
| 
         @@ -51,5 +83,14 @@ module SchemaPlus::ActiveRecord 
     | 
|
| 
       51 
83 
     | 
    
         
             
                  add_index(table_name, column_name, options)
         
     | 
| 
       52 
84 
     | 
    
         
             
                end
         
     | 
| 
       53 
85 
     | 
    
         | 
| 
      
 86 
     | 
    
         
            +
                def remove_auto_index_if_exists(table_name, column_name)
         
     | 
| 
      
 87 
     | 
    
         
            +
                  name = auto_index_name(table_name, column_name)
         
     | 
| 
      
 88 
     | 
    
         
            +
                  remove_index(table_name, :name => name) if index_exists?(table_name, column_name, :name => name)
         
     | 
| 
      
 89 
     | 
    
         
            +
                end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                def auto_index_name(table_name, column_name)
         
     | 
| 
      
 92 
     | 
    
         
            +
                  ConnectionAdapters::ForeignKeyDefinition.auto_index_name(table_name, column_name)
         
     | 
| 
      
 93 
     | 
    
         
            +
                end
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
       54 
95 
     | 
    
         
             
              end
         
     | 
| 
       55 
96 
     | 
    
         
             
            end
         
     | 
| 
         @@ -35,14 +35,6 @@ module SchemaPlus 
     | 
|
| 
       35 
35 
     | 
    
         
             
                        adapter_module = SchemaPlus::ActiveRecord::ConnectionAdapters.const_get(adapter)
         
     | 
| 
       36 
36 
     | 
    
         
             
                        self.class.send(:include, adapter_module) unless self.class.include?(adapter_module)
         
     | 
| 
       37 
37 
     | 
    
         
             
                        self.post_initialize if self.respond_to? :post_initialize
         
     | 
| 
       38 
     | 
    
         
            -
                        # rails 3.1 defines a separate Mysql2IndexDefinition which is
         
     | 
| 
       39 
     | 
    
         
            -
                        # compatible with the monkey patches; but the definition only
         
     | 
| 
       40 
     | 
    
         
            -
                        # appears once the adapter is loaded.  so wait til now to check
         
     | 
| 
       41 
     | 
    
         
            -
                        # if that constant exists, then include the patches
         
     | 
| 
       42 
     | 
    
         
            -
                        if mysql2index = ::ActiveRecord::ConnectionAdapters::Mysql2IndexDefinition rescue nil # rescues NameError
         
     | 
| 
       43 
     | 
    
         
            -
                          monkeypatch = SchemaPlus::ActiveRecord::ConnectionAdapters::IndexDefinition
         
     | 
| 
       44 
     | 
    
         
            -
                          mysql2index.send(:include, monkeypatch) unless mysql2index.include? monkeypatch
         
     | 
| 
       45 
     | 
    
         
            -
                        end
         
     | 
| 
       46 
38 
     | 
    
         | 
| 
       47 
39 
     | 
    
         
             
                        if adapter == 'PostgresqlAdapter'
         
     | 
| 
       48 
40 
     | 
    
         
             
                          ::ActiveRecord::ConnectionAdapters::PostgreSQLColumn.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::PostgreSQLColumn) unless ::ActiveRecord::ConnectionAdapters::PostgreSQLColumn.include?(SchemaPlus::ActiveRecord::ConnectionAdapters::PostgreSQLColumn)
         
     | 
| 
         @@ -57,6 +49,7 @@ module SchemaPlus 
     | 
|
| 
       57 
49 
     | 
    
         
             
                    # Create a view given the SQL definition.  Specify :force => true
         
     | 
| 
       58 
50 
     | 
    
         
             
                    # to first drop the view if it already exists.
         
     | 
| 
       59 
51 
     | 
    
         
             
                    def create_view(view_name, definition, options={})
         
     | 
| 
      
 52 
     | 
    
         
            +
                      definition = definition.to_sql if definition.respond_to? :to_sql
         
     | 
| 
       60 
53 
     | 
    
         
             
                      execute "DROP VIEW IF EXISTS #{quote_table_name(view_name)}" if options[:force]
         
     | 
| 
       61 
54 
     | 
    
         
             
                      execute "CREATE VIEW #{quote_table_name(view_name)} AS #{definition}"
         
     | 
| 
       62 
55 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -66,21 +59,6 @@ module SchemaPlus 
     | 
|
| 
       66 
59 
     | 
    
         
             
                      execute "DROP VIEW #{quote_table_name(view_name)}"
         
     | 
| 
       67 
60 
     | 
    
         
             
                    end
         
     | 
| 
       68 
61 
     | 
    
         | 
| 
       69 
     | 
    
         
            -
                    #--
         
     | 
| 
       70 
     | 
    
         
            -
                    # these are all expected to be defined by subclasses, listing them
         
     | 
| 
       71 
     | 
    
         
            -
                    # here only as templates.
         
     | 
| 
       72 
     | 
    
         
            -
                    #++
         
     | 
| 
       73 
     | 
    
         
            -
                    # Returns a list of all views (abstract)
         
     | 
| 
       74 
     | 
    
         
            -
                    def views(name = nil) [] end
         
     | 
| 
       75 
     | 
    
         
            -
                    # Returns the SQL definition of a given view (abstract)
         
     | 
| 
       76 
     | 
    
         
            -
                    def view_definition(view_name, name = nil) end
         
     | 
| 
       77 
     | 
    
         
            -
                    # Return the ForeignKeyDefinition objects for foreign key
         
     | 
| 
       78 
     | 
    
         
            -
                    # constraints defined on this table (abstract)
         
     | 
| 
       79 
     | 
    
         
            -
                    def foreign_keys(table_name, name = nil) [] end
         
     | 
| 
       80 
     | 
    
         
            -
                    # Return the ForeignKeyDefinition objects for foreign key
         
     | 
| 
       81 
     | 
    
         
            -
                    # constraints defined on other tables that reference this table
         
     | 
| 
       82 
     | 
    
         
            -
                    # (abstract)
         
     | 
| 
       83 
     | 
    
         
            -
                    def reverse_foreign_keys(table_name, name = nil) [] end
         
     | 
| 
       84 
62 
     | 
    
         | 
| 
       85 
63 
     | 
    
         
             
                    # Define a foreign key constraint.  Valid options are :on_update,
         
     | 
| 
       86 
64 
     | 
    
         
             
                    # :on_delete, and :deferrable, with values as described at
         
     | 
| 
         @@ -117,6 +95,31 @@ module SchemaPlus 
     | 
|
| 
       117 
95 
     | 
    
         
             
                      drop_table_without_schema_plus(name)
         
     | 
| 
       118 
96 
     | 
    
         
             
                    end
         
     | 
| 
       119 
97 
     | 
    
         | 
| 
      
 98 
     | 
    
         
            +
                    # called from individual adpaters, after renaming table from old
         
     | 
| 
      
 99 
     | 
    
         
            +
                    # name to
         
     | 
| 
      
 100 
     | 
    
         
            +
                    def rename_indexes_and_foreign_keys(oldname, newname) #:nodoc:
         
     | 
| 
      
 101 
     | 
    
         
            +
                      indexes(newname).select{|index| index.name == index_name(oldname, index.columns)}.each do |index|
         
     | 
| 
      
 102 
     | 
    
         
            +
                        rename_index(newname, index.name, index_name(newname, index.columns))
         
     | 
| 
      
 103 
     | 
    
         
            +
                      end
         
     | 
| 
      
 104 
     | 
    
         
            +
                      foreign_keys(newname).each do |fk|
         
     | 
| 
      
 105 
     | 
    
         
            +
                        index = indexes(newname).find{|index| index.name == ForeignKeyDefinition.auto_index_name(oldname, index.columns)}
         
     | 
| 
      
 106 
     | 
    
         
            +
                        begin
         
     | 
| 
      
 107 
     | 
    
         
            +
                          remove_foreign_key(newname, fk.name)
         
     | 
| 
      
 108 
     | 
    
         
            +
                        rescue NotImplementedError
         
     | 
| 
      
 109 
     | 
    
         
            +
                          # sqlite3 can't remove foreign keys, so just skip it
         
     | 
| 
      
 110 
     | 
    
         
            +
                        end
         
     | 
| 
      
 111 
     | 
    
         
            +
                        # rename the index only when the fk constraint doesn't exist.
         
     | 
| 
      
 112 
     | 
    
         
            +
                        # mysql doesn't allow the rename (which is a delete & add)
         
     | 
| 
      
 113 
     | 
    
         
            +
                        # if the index is on a foreign key constraint
         
     | 
| 
      
 114 
     | 
    
         
            +
                        rename_index(newname, index.name, ForeignKeyDefinition.auto_index_name(newname, index.columns)) if index
         
     | 
| 
      
 115 
     | 
    
         
            +
                        begin
         
     | 
| 
      
 116 
     | 
    
         
            +
                          add_foreign_key(newname, fk.column_names, fk.references_table_name, fk.references_column_names, :name => newname, :on_update => fk.on_update, :on_delete => fk.on_delete, :deferrable => fk.deferrable)
         
     | 
| 
      
 117 
     | 
    
         
            +
                        rescue NotImplementedError
         
     | 
| 
      
 118 
     | 
    
         
            +
                          # sqlite3 can't add foreign keys, so just skip it
         
     | 
| 
      
 119 
     | 
    
         
            +
                        end
         
     | 
| 
      
 120 
     | 
    
         
            +
                      end
         
     | 
| 
      
 121 
     | 
    
         
            +
                    end
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
       120 
123 
     | 
    
         
             
                    # Returns true if the database supports parital indexes (abstract; only
         
     | 
| 
       121 
124 
     | 
    
         
             
                    # Postgresql returns true)
         
     | 
| 
       122 
125 
     | 
    
         
             
                    def supports_partial_indexes?
         
     | 
| 
         @@ -146,14 +149,6 @@ module SchemaPlus 
     | 
|
| 
       146 
149 
     | 
    
         
             
                      end
         
     | 
| 
       147 
150 
     | 
    
         
             
                    end
         
     | 
| 
       148 
151 
     | 
    
         | 
| 
       149 
     | 
    
         
            -
                    def default_expr_valid?(expr)
         
     | 
| 
       150 
     | 
    
         
            -
                      # override in database specific adaptor
         
     | 
| 
       151 
     | 
    
         
            -
                    end
         
     | 
| 
       152 
     | 
    
         
            -
             
     | 
| 
       153 
     | 
    
         
            -
                    def sql_for_function(function_name)
         
     | 
| 
       154 
     | 
    
         
            -
                      # override in database specific adaptor
         
     | 
| 
       155 
     | 
    
         
            -
                    end
         
     | 
| 
       156 
     | 
    
         
            -
             
     | 
| 
       157 
152 
     | 
    
         
             
                    # This is define in rails 3.x, but not in rails2.x
         
     | 
| 
       158 
153 
     | 
    
         
             
                    unless defined? ::ActiveRecord::ConnectionAdapters::SchemaStatements::index_name_exists?
         
     | 
| 
       159 
154 
     | 
    
         
             
                      # File activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb, line 403
         
     | 
| 
         @@ -163,6 +158,40 @@ module SchemaPlus 
     | 
|
| 
       163 
158 
     | 
    
         
             
                        indexes(table_name).detect { |i| i.name == index_name }
         
     | 
| 
       164 
159 
     | 
    
         
             
                      end
         
     | 
| 
       165 
160 
     | 
    
         
             
                    end
         
     | 
| 
      
 161 
     | 
    
         
            +
                    
         
     | 
| 
      
 162 
     | 
    
         
            +
                    #####################################################################
         
     | 
| 
      
 163 
     | 
    
         
            +
                    #
         
     | 
| 
      
 164 
     | 
    
         
            +
                    # The functions below here are abstract; each subclass should
         
     | 
| 
      
 165 
     | 
    
         
            +
                    # define them all. Defining them here only for reference.
         
     | 
| 
      
 166 
     | 
    
         
            +
                    #
         
     | 
| 
      
 167 
     | 
    
         
            +
                    
         
     | 
| 
      
 168 
     | 
    
         
            +
                    # (abstract) Returns the names of all views, as an array of strings
         
     | 
| 
      
 169 
     | 
    
         
            +
                    def views(name = nil) raise "Internal Error: Connection adapter didn't override abstract function"; [] end
         
     | 
| 
      
 170 
     | 
    
         
            +
             
     | 
| 
      
 171 
     | 
    
         
            +
                    # (abstract) Returns the SQL definition of a given view.  This is
         
     | 
| 
      
 172 
     | 
    
         
            +
                    # the literal SQL would come after 'CREATVE VIEW viewname AS ' in
         
     | 
| 
      
 173 
     | 
    
         
            +
                    # the SQL statement to create a view.
         
     | 
| 
      
 174 
     | 
    
         
            +
                    def view_definition(view_name, name = nil) raise "Internal Error: Connection adapter didn't override abstract function"; end
         
     | 
| 
      
 175 
     | 
    
         
            +
             
     | 
| 
      
 176 
     | 
    
         
            +
                    # (abstract) Return the ForeignKeyDefinition objects for foreign key
         
     | 
| 
      
 177 
     | 
    
         
            +
                    # constraints defined on this table
         
     | 
| 
      
 178 
     | 
    
         
            +
                    def foreign_keys(table_name, name = nil) raise "Internal Error: Connection adapter didn't override abstract function"; [] end
         
     | 
| 
      
 179 
     | 
    
         
            +
             
     | 
| 
      
 180 
     | 
    
         
            +
                    # (abstract) Return the ForeignKeyDefinition objects for foreign key
         
     | 
| 
      
 181 
     | 
    
         
            +
                    # constraints defined on other tables that reference this table
         
     | 
| 
      
 182 
     | 
    
         
            +
                    def reverse_foreign_keys(table_name, name = nil) raise "Internal Error: Connection adapter didn't override abstract function"; [] end
         
     | 
| 
      
 183 
     | 
    
         
            +
             
     | 
| 
      
 184 
     | 
    
         
            +
                    # (abstract) Return true if the passed expression can be used as a column
         
     | 
| 
      
 185 
     | 
    
         
            +
                    # default value.  (For most databases the specific expression
         
     | 
| 
      
 186 
     | 
    
         
            +
                    # doesn't matter, and the adapter's function would return a
         
     | 
| 
      
 187 
     | 
    
         
            +
                    # constant true if default expressions are supported or false if
         
     | 
| 
      
 188 
     | 
    
         
            +
                    # they're not.)
         
     | 
| 
      
 189 
     | 
    
         
            +
                    def default_expr_valid?(expr) raise "Internal Error: Connection adapter didn't override abstract function"; end
         
     | 
| 
      
 190 
     | 
    
         
            +
             
     | 
| 
      
 191 
     | 
    
         
            +
                    # (abstract) Return SQL definition for a given canonical function_name symbol.
         
     | 
| 
      
 192 
     | 
    
         
            +
                    # Currently, the only function to support is :now, which should
         
     | 
| 
      
 193 
     | 
    
         
            +
                    # return a DATETIME object for the current time.
         
     | 
| 
      
 194 
     | 
    
         
            +
                    def sql_for_function(function_name) raise "Internal Error: Connection adapter didn't override abstract function"; end
         
     | 
| 
       166 
195 
     | 
    
         | 
| 
       167 
196 
     | 
    
         
             
                  end
         
     | 
| 
       168 
197 
     | 
    
         
             
                end
         
     | 
| 
         @@ -31,7 +31,7 @@ module SchemaPlus 
     | 
|
| 
       31 
31 
     | 
    
         
             
                    # possible values.
         
     | 
| 
       32 
32 
     | 
    
         
             
                    attr_reader :on_update
         
     | 
| 
       33 
33 
     | 
    
         | 
| 
       34 
     | 
    
         
            -
                    # The  
     | 
| 
      
 34 
     | 
    
         
            +
                    # The ON_DELETE behavior for the constraint.  See above for the
         
     | 
| 
       35 
35 
     | 
    
         
             
                    # possible values.
         
     | 
| 
       36 
36 
     | 
    
         
             
                    attr_reader :on_delete
         
     | 
| 
       37 
37 
     | 
    
         | 
| 
         @@ -39,7 +39,7 @@ module SchemaPlus 
     | 
|
| 
       39 
39 
     | 
    
         
             
                    attr_reader :deferrable
         
     | 
| 
       40 
40 
     | 
    
         | 
| 
       41 
41 
     | 
    
         
             
                    # :enddoc:
         
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
       43 
43 
     | 
    
         
             
                    ACTIONS = { :cascade => "CASCADE", :restrict => "RESTRICT", :set_null => "SET NULL", :set_default => "SET DEFAULT", :no_action => "NO ACTION" }.freeze
         
     | 
| 
       44 
44 
     | 
    
         | 
| 
       45 
45 
     | 
    
         
             
                    def initialize(name, table_name, column_names, references_table_name, references_column_names, on_update = nil, on_delete = nil, deferrable = nil)
         
     | 
| 
         @@ -105,6 +105,11 @@ module SchemaPlus 
     | 
|
| 
       105 
105 
     | 
    
         
             
                    def __unquote(value)
         
     | 
| 
       106 
106 
     | 
    
         
             
                      value.to_s.sub(/^["`](.*)["`]$/, '\1')
         
     | 
| 
       107 
107 
     | 
    
         
             
                    end
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
                    def self.auto_index_name(table_name, column_name)
         
     | 
| 
      
 110 
     | 
    
         
            +
                      "fk__#{table_name}_#{Array.wrap(column_name).join('_and_')}"
         
     | 
| 
      
 111 
     | 
    
         
            +
                    end
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
       108 
113 
     | 
    
         
             
                  end
         
     | 
| 
       109 
114 
     | 
    
         
             
                end
         
     | 
| 
       110 
115 
     | 
    
         
             
              end
         
     | 
| 
         @@ -22,7 +22,7 @@ module SchemaPlus 
     | 
|
| 
       22 
22 
     | 
    
         
             
                      # same args as add_index(table_name, column_names, options)
         
     | 
| 
       23 
23 
     | 
    
         
             
                      if args.length == 3 and Hash === args.last
         
     | 
| 
       24 
24 
     | 
    
         
             
                        table_name, column_names, options = args + [{}]
         
     | 
| 
       25 
     | 
    
         
            -
                        initialize_without_schema_plus(table_name, options[:name], options[:unique], column_names, options[:lengths])
         
     | 
| 
      
 25 
     | 
    
         
            +
                        initialize_without_schema_plus(table_name, options[:name], options[:unique], column_names, options[:lengths], options[:orders])
         
     | 
| 
       26 
26 
     | 
    
         
             
                        @conditions = options[:conditions]
         
     | 
| 
       27 
27 
     | 
    
         
             
                        @expression = options[:expression]
         
     | 
| 
       28 
28 
     | 
    
         
             
                        @kind = options[:kind]
         
     | 
| 
         @@ -48,6 +48,7 @@ module SchemaPlus 
     | 
|
| 
       48 
48 
     | 
    
         | 
| 
       49 
49 
     | 
    
         
             
                    # tests if the corresponding indexes would be the same
         
     | 
| 
       50 
50 
     | 
    
         
             
                    def ==(other)
         
     | 
| 
      
 51 
     | 
    
         
            +
                      return false if other.nil?
         
     | 
| 
       51 
52 
     | 
    
         
             
                      return false unless self.name == other.name
         
     | 
| 
       52 
53 
     | 
    
         
             
                      return false unless Array.wrap(self.columns).collect(&:to_s).sort == Array.wrap(other.columns).collect(&:to_s).sort
         
     | 
| 
       53 
54 
     | 
    
         
             
                      return false unless !!self.unique == !!other.unique
         
     | 
| 
         @@ -12,6 +12,8 @@ module SchemaPlus 
     | 
|
| 
       12 
12 
     | 
    
         
             
                      base.class_eval do
         
     | 
| 
       13 
13 
     | 
    
         
             
                        alias_method_chain :tables, :schema_plus
         
     | 
| 
       14 
14 
     | 
    
         
             
                        alias_method_chain :remove_column, :schema_plus
         
     | 
| 
      
 15 
     | 
    
         
            +
                        alias_method_chain :rename_table, :schema_plus
         
     | 
| 
      
 16 
     | 
    
         
            +
                        alias_method_chain :exec_stmt, :schema_plus rescue nil # only defined for mysql not mysql2
         
     | 
| 
       15 
17 
     | 
    
         
             
                      end
         
     | 
| 
       16 
18 
     | 
    
         
             
                    end
         
     | 
| 
       17 
19 
     | 
    
         | 
| 
         @@ -26,11 +28,27 @@ module SchemaPlus 
     | 
|
| 
       26 
28 
     | 
    
         
             
                      remove_column_without_schema_plus(table_name, column_name)
         
     | 
| 
       27 
29 
     | 
    
         
             
                    end
         
     | 
| 
       28 
30 
     | 
    
         | 
| 
      
 31 
     | 
    
         
            +
                    def rename_table_with_schema_plus(oldname, newname)
         
     | 
| 
      
 32 
     | 
    
         
            +
                      rename_table_without_schema_plus(oldname, newname)
         
     | 
| 
      
 33 
     | 
    
         
            +
                      rename_indexes_and_foreign_keys(oldname, newname)
         
     | 
| 
      
 34 
     | 
    
         
            +
                    end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                    def exec_stmt_with_schema_plus(sql, name, binds, &block)
         
     | 
| 
      
 37 
     | 
    
         
            +
                      if binds.any?{ |col, val| val.equal? ::ActiveRecord::DB_DEFAULT}
         
     | 
| 
      
 38 
     | 
    
         
            +
                        binds.each_with_index do |(col, val), i|
         
     | 
| 
      
 39 
     | 
    
         
            +
                          if val.equal? ::ActiveRecord::DB_DEFAULT
         
     | 
| 
      
 40 
     | 
    
         
            +
                            sql = sql.sub(/(([^?]*?){#{i}}[^?]*)\?/, "\\1DEFAULT")
         
     | 
| 
      
 41 
     | 
    
         
            +
                          end
         
     | 
| 
      
 42 
     | 
    
         
            +
                        end
         
     | 
| 
      
 43 
     | 
    
         
            +
                        binds = binds.reject{|col, val| val.equal? ::ActiveRecord::DB_DEFAULT}
         
     | 
| 
      
 44 
     | 
    
         
            +
                      end
         
     | 
| 
      
 45 
     | 
    
         
            +
                      exec_stmt_without_schema_plus(sql, name, binds, &block)
         
     | 
| 
      
 46 
     | 
    
         
            +
                    end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
       29 
48 
     | 
    
         
             
                    def remove_foreign_key(table_name, foreign_key_name, options = {})
         
     | 
| 
       30 
49 
     | 
    
         
             
                      execute "ALTER TABLE #{quote_table_name(table_name)} DROP FOREIGN KEY #{foreign_key_name}"
         
     | 
| 
       31 
50 
     | 
    
         
             
                    end
         
     | 
| 
       32 
51 
     | 
    
         | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
       34 
52 
     | 
    
         
             
                    def foreign_keys(table_name, name = nil)
         
     | 
| 
       35 
53 
     | 
    
         
             
                      results = execute("SHOW CREATE TABLE #{quote_table_name(table_name)}", name)
         
     | 
| 
       36 
54 
     | 
    
         | 
| 
         @@ -25,10 +25,10 @@ module SchemaPlus 
     | 
|
| 
       25 
25 
     | 
    
         | 
| 
       26 
26 
     | 
    
         
             
                    module ClassMethods
         
     | 
| 
       27 
27 
     | 
    
         
             
                      def extract_value_from_default_with_schema_plus(default)
         
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
       29 
29 
     | 
    
         | 
| 
       30 
30 
     | 
    
         
             
                        value = extract_value_from_default_without_schema_plus(default)
         
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
       32 
32 
     | 
    
         
             
                        # in some cases (e.g. if change_column_default(table, column,
         
     | 
| 
       33 
33 
     | 
    
         
             
                        # nil) is used), postgresql will return NULL::xxxxx (rather
         
     | 
| 
       34 
34 
     | 
    
         
             
                        # than nil) for a null default -- make sure we treat it as nil,
         
     | 
| 
         @@ -50,6 +50,8 @@ module SchemaPlus 
     | 
|
| 
       50 
50 
     | 
    
         
             
                    def self.included(base) #:nodoc:
         
     | 
| 
       51 
51 
     | 
    
         
             
                      base.class_eval do
         
     | 
| 
       52 
52 
     | 
    
         
             
                        remove_method :indexes
         
     | 
| 
      
 53 
     | 
    
         
            +
                        alias_method_chain :rename_table, :schema_plus
         
     | 
| 
      
 54 
     | 
    
         
            +
                        alias_method_chain :exec_cache, :schema_plus
         
     | 
| 
       53 
55 
     | 
    
         
             
                      end
         
     | 
| 
       54 
56 
     | 
    
         
             
                    end
         
     | 
| 
       55 
57 
     | 
    
         | 
| 
         @@ -74,13 +76,24 @@ module SchemaPlus 
     | 
|
| 
       74 
76 
     | 
    
         
             
                      index_type = options[:unique] ? "UNIQUE" : ""
         
     | 
| 
       75 
77 
     | 
    
         
             
                      index_name = options[:name] || index_name(table_name, column_names)
         
     | 
| 
       76 
78 
     | 
    
         
             
                      conditions = options[:conditions]
         
     | 
| 
      
 79 
     | 
    
         
            +
                      kind       = options[:kind]
         
     | 
| 
       77 
80 
     | 
    
         | 
| 
       78 
     | 
    
         
            -
                      if options[:expression] then
         
     | 
| 
       79 
     | 
    
         
            -
                         
     | 
| 
      
 81 
     | 
    
         
            +
                      if expression = options[:expression] then
         
     | 
| 
      
 82 
     | 
    
         
            +
                        # Wrap expression in parentheses if necessary
         
     | 
| 
      
 83 
     | 
    
         
            +
                        expression = "(#{expression})" if expression !~ /(using|with|tablespace|where)/i
         
     | 
| 
      
 84 
     | 
    
         
            +
                        expression = "USING #{kind} #{expression}" if kind
         
     | 
| 
      
 85 
     | 
    
         
            +
                        expression = "#{expression} WHERE #{conditions}" if conditions
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                        sql = "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} #{expression}"
         
     | 
| 
       80 
88 
     | 
    
         
             
                      else
         
     | 
| 
       81 
     | 
    
         
            -
                         
     | 
| 
      
 89 
     | 
    
         
            +
                        option_strings = Hash[column_names.map {|name| [name, '']}]
         
     | 
| 
      
 90 
     | 
    
         
            +
                        option_strings = add_index_sort_order(option_strings, column_names, options)
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                        quoted_column_names = column_names.map { |e| (options[:case_sensitive] == false && e.to_s !~ /_id$/ ? "LOWER(#{quote_column_name(e)})" : quote_column_name(e)) + option_strings[e] }
         
     | 
| 
      
 93 
     | 
    
         
            +
                        expression = "(#{quoted_column_names.join(', ')})"
         
     | 
| 
      
 94 
     | 
    
         
            +
                        expression = "USING #{kind} #{expression}" if kind
         
     | 
| 
       82 
95 
     | 
    
         | 
| 
       83 
     | 
    
         
            -
                        sql = "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)}  
     | 
| 
      
 96 
     | 
    
         
            +
                        sql = "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} #{expression}"
         
     | 
| 
       84 
97 
     | 
    
         
             
                        sql += " WHERE (#{ ::ActiveRecord::Base.send(:sanitize_sql, conditions, quote_table_name(table_name)) })" if conditions
         
     | 
| 
       85 
98 
     | 
    
         
             
                      end
         
     | 
| 
       86 
99 
     | 
    
         
             
                      execute sql
         
     | 
| 
         @@ -92,23 +105,28 @@ module SchemaPlus 
     | 
|
| 
       92 
105 
     | 
    
         
             
                      true
         
     | 
| 
       93 
106 
     | 
    
         
             
                    end
         
     | 
| 
       94 
107 
     | 
    
         | 
| 
      
 108 
     | 
    
         
            +
                    # This method entirely duplicated from AR's postgresql_adapter.c,
         
     | 
| 
      
 109 
     | 
    
         
            +
                    # but includes the extra bit to determine the column name for a
         
     | 
| 
      
 110 
     | 
    
         
            +
                    # case-insensitive index.  (Haven't come up with any clever way to
         
     | 
| 
      
 111 
     | 
    
         
            +
                    # only code up the case-insensitive column name bit here and
         
     | 
| 
      
 112 
     | 
    
         
            +
                    # otherwise use the existing method.)
         
     | 
| 
       95 
113 
     | 
    
         
             
                    def indexes(table_name, name = nil) #:nodoc:
         
     | 
| 
       96 
     | 
    
         
            -
                      schemas = schema_search_path.split(/,/).map { |p| quote(p) }.join(',')
         
     | 
| 
       97 
114 
     | 
    
         
             
                      result = query(<<-SQL, name)
         
     | 
| 
       98 
     | 
    
         
            -
             
     | 
| 
       99 
     | 
    
         
            -
             
     | 
| 
       100 
     | 
    
         
            -
             
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
                       SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid), t.oid,
         
     | 
| 
      
 117 
     | 
    
         
            +
                              m.amname, pg_get_expr(d.indpred, t.oid), pg_get_expr(d.indexprs, t.oid)
         
     | 
| 
      
 118 
     | 
    
         
            +
                       FROM pg_class t
         
     | 
| 
      
 119 
     | 
    
         
            +
                       INNER JOIN pg_index d ON t.oid = d.indrelid
         
     | 
| 
      
 120 
     | 
    
         
            +
                       INNER JOIN pg_class i ON d.indexrelid = i.oid
         
     | 
| 
      
 121 
     | 
    
         
            +
                       INNER JOIN pg_am m ON i.relam = m.oid
         
     | 
| 
       101 
122 
     | 
    
         
             
                       WHERE i.relkind = 'i'
         
     | 
| 
       102 
     | 
    
         
            -
                         AND i.relam = m.oid
         
     | 
| 
       103 
     | 
    
         
            -
                         AND d.indexrelid = i.oid
         
     | 
| 
       104 
123 
     | 
    
         
             
                         AND d.indisprimary = 'f'
         
     | 
| 
       105 
     | 
    
         
            -
                         AND t.oid = d.indrelid
         
     | 
| 
       106 
124 
     | 
    
         
             
                         AND t.relname = '#{table_name}'
         
     | 
| 
       107 
     | 
    
         
            -
                         AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname  
     | 
| 
      
 125 
     | 
    
         
            +
                         AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname = ANY (current_schemas(false)) )
         
     | 
| 
       108 
126 
     | 
    
         
             
                      ORDER BY i.relname
         
     | 
| 
       109 
127 
     | 
    
         
             
                      SQL
         
     | 
| 
       110 
128 
     | 
    
         | 
| 
       111 
     | 
    
         
            -
                      result.map do |(index_name, is_unique, indkey,  
     | 
| 
      
 129 
     | 
    
         
            +
                      result.map do |(index_name, is_unique, indkey, inddef, oid, kind, conditions, expression)|
         
     | 
| 
       112 
130 
     | 
    
         
             
                        unique = (is_unique == 't')
         
     | 
| 
       113 
131 
     | 
    
         
             
                        index_keys = indkey.split(" ")
         
     | 
| 
       114 
132 
     | 
    
         | 
| 
         @@ -120,12 +138,20 @@ module SchemaPlus 
     | 
|
| 
       120 
138 
     | 
    
         
             
                        SQL
         
     | 
| 
       121 
139 
     | 
    
         | 
| 
       122 
140 
     | 
    
         
             
                        column_names = columns.values_at(*index_keys).compact
         
     | 
| 
      
 141 
     | 
    
         
            +
                        # extract column name from the expression, for a
         
     | 
| 
      
 142 
     | 
    
         
            +
                        # case-insensitive 
         
     | 
| 
       123 
143 
     | 
    
         
             
                        if md = expression.try(:match, /^lower\(\(?([^)]+)\)?(::text)?\)$/i)
         
     | 
| 
       124 
144 
     | 
    
         
             
                          column_names << md[1]
         
     | 
| 
       125 
145 
     | 
    
         
             
                        end
         
     | 
| 
      
 146 
     | 
    
         
            +
                        
         
     | 
| 
      
 147 
     | 
    
         
            +
                        # add info on sort order for columns (only desc order is explicitly specified, asc is the default)
         
     | 
| 
      
 148 
     | 
    
         
            +
                        desc_order_columns = inddef.scan(/(\w+) DESC/).flatten
         
     | 
| 
      
 149 
     | 
    
         
            +
                        orders = desc_order_columns.any? ? Hash[column_names.map {|column| [column, desc_order_columns.include?(column) ? :desc : :asc]}] : {}
         
     | 
| 
      
 150 
     | 
    
         
            +
             
     | 
| 
       126 
151 
     | 
    
         
             
                        ::ActiveRecord::ConnectionAdapters::IndexDefinition.new(table_name, column_names,
         
     | 
| 
       127 
152 
     | 
    
         
             
                                                                                :name => index_name,
         
     | 
| 
       128 
153 
     | 
    
         
             
                                                                                :unique => unique,
         
     | 
| 
      
 154 
     | 
    
         
            +
                                                                                :orders => orders,
         
     | 
| 
       129 
155 
     | 
    
         
             
                                                                                :conditions => conditions,
         
     | 
| 
       130 
156 
     | 
    
         
             
                                                                                :case_sensitive => !(expression =~ /lower/i),
         
     | 
| 
       131 
157 
     | 
    
         
             
                                                                                :kind => kind.downcase == "btree" ? nil : kind,
         
     | 
| 
         @@ -133,6 +159,30 @@ module SchemaPlus 
     | 
|
| 
       133 
159 
     | 
    
         
             
                      end
         
     | 
| 
       134 
160 
     | 
    
         
             
                    end
         
     | 
| 
       135 
161 
     | 
    
         | 
| 
      
 162 
     | 
    
         
            +
                    def rename_table_with_schema_plus(oldname, newname) #:nodoc:
         
     | 
| 
      
 163 
     | 
    
         
            +
                      rename_table_without_schema_plus(oldname, newname)
         
     | 
| 
      
 164 
     | 
    
         
            +
                      rename_indexes_and_foreign_keys(oldname, newname)
         
     | 
| 
      
 165 
     | 
    
         
            +
                    end
         
     | 
| 
      
 166 
     | 
    
         
            +
             
     | 
| 
      
 167 
     | 
    
         
            +
                    # Prepass to replace each ActiveRecord::DB_DEFAULT with a literal
         
     | 
| 
      
 168 
     | 
    
         
            +
                    # DEFAULT in the sql string.  (The underlying pg gem provides no
         
     | 
| 
      
 169 
     | 
    
         
            +
                    # way to bind a value that will replace $n with DEFAULT)
         
     | 
| 
      
 170 
     | 
    
         
            +
                    def exec_cache_with_schema_plus(sql, binds)
         
     | 
| 
      
 171 
     | 
    
         
            +
                      if binds.any?{ |col, val| val.equal? ::ActiveRecord::DB_DEFAULT}
         
     | 
| 
      
 172 
     | 
    
         
            +
                        j = 0
         
     | 
| 
      
 173 
     | 
    
         
            +
                        binds.each_with_index do |(col, val), i|
         
     | 
| 
      
 174 
     | 
    
         
            +
                        if val.equal? ::ActiveRecord::DB_DEFAULT
         
     | 
| 
      
 175 
     | 
    
         
            +
                          sql = sql.sub(/\$#{i+1}/, 'DEFAULT')
         
     | 
| 
      
 176 
     | 
    
         
            +
                        else
         
     | 
| 
      
 177 
     | 
    
         
            +
                          sql = sql.sub(/\$#{i+1}/, "$#{j+1}") if i != j
         
     | 
| 
      
 178 
     | 
    
         
            +
                          j += 1
         
     | 
| 
      
 179 
     | 
    
         
            +
                        end
         
     | 
| 
      
 180 
     | 
    
         
            +
                        end
         
     | 
| 
      
 181 
     | 
    
         
            +
                        binds = binds.reject{|col, val| val.equal? ::ActiveRecord::DB_DEFAULT}
         
     | 
| 
      
 182 
     | 
    
         
            +
                      end
         
     | 
| 
      
 183 
     | 
    
         
            +
                      exec_cache_without_schema_plus(sql, binds)
         
     | 
| 
      
 184 
     | 
    
         
            +
                    end
         
     | 
| 
      
 185 
     | 
    
         
            +
             
     | 
| 
       136 
186 
     | 
    
         
             
                    def foreign_keys(table_name, name = nil) #:nodoc:
         
     | 
| 
       137 
187 
     | 
    
         
             
                      load_foreign_keys(<<-SQL, name)
         
     | 
| 
       138 
188 
     | 
    
         
             
                    SELECT f.conname, pg_get_constraintdef(f.oid), t.relname
         
     | 
| 
         @@ -140,6 +190,7 @@ module SchemaPlus 
     | 
|
| 
       140 
190 
     | 
    
         
             
                     WHERE f.conrelid = t.oid
         
     | 
| 
       141 
191 
     | 
    
         
             
                       AND f.contype = 'f'
         
     | 
| 
       142 
192 
     | 
    
         
             
                       AND t.relname = '#{table_name}'
         
     | 
| 
      
 193 
     | 
    
         
            +
                       AND t.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname = ANY (current_schemas(false)) )
         
     | 
| 
       143 
194 
     | 
    
         
             
                      SQL
         
     | 
| 
       144 
195 
     | 
    
         
             
                    end
         
     | 
| 
       145 
196 
     | 
    
         | 
| 
         @@ -151,15 +202,15 @@ module SchemaPlus 
     | 
|
| 
       151 
202 
     | 
    
         
             
                       AND f.conrelid = t2.oid
         
     | 
| 
       152 
203 
     | 
    
         
             
                       AND f.contype = 'f'
         
     | 
| 
       153 
204 
     | 
    
         
             
                       AND t.relname = '#{table_name}'
         
     | 
| 
      
 205 
     | 
    
         
            +
                       AND t.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname = ANY (current_schemas(false)) )
         
     | 
| 
       154 
206 
     | 
    
         
             
                      SQL
         
     | 
| 
       155 
207 
     | 
    
         
             
                    end
         
     | 
| 
       156 
208 
     | 
    
         | 
| 
       157 
209 
     | 
    
         
             
                    def views(name = nil) #:nodoc:
         
     | 
| 
       158 
     | 
    
         
            -
                      schemas = schema_search_path.split(/,/).map { |p| quote(p) }.join(',')
         
     | 
| 
       159 
210 
     | 
    
         
             
                      query(<<-SQL, name).map { |row| row[0] }
         
     | 
| 
       160 
211 
     | 
    
         
             
                    SELECT viewname
         
     | 
| 
       161 
212 
     | 
    
         
             
                      FROM pg_views
         
     | 
| 
       162 
     | 
    
         
            -
                     WHERE schemaname  
     | 
| 
      
 213 
     | 
    
         
            +
                     WHERE schemaname = ANY (current_schemas(false))
         
     | 
| 
       163 
214 
     | 
    
         
             
                      SQL
         
     | 
| 
       164 
215 
     | 
    
         
             
                    end
         
     | 
| 
       165 
216 
     | 
    
         |