schema_plus 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.travis.yml +29 -0
  4. data/README.md +19 -0
  5. data/gemfiles/rails-3.2/Gemfile.mysql +7 -1
  6. data/gemfiles/rails-3.2/Gemfile.mysql2 +7 -1
  7. data/gemfiles/rails-3.2/Gemfile.postgresql +7 -1
  8. data/gemfiles/rails-3.2/Gemfile.sqlite3 +7 -1
  9. data/gemfiles/rails-4.0/Gemfile.mysql2 +7 -1
  10. data/gemfiles/rails-4.0/Gemfile.postgresql +7 -1
  11. data/gemfiles/rails-4.0/Gemfile.sqlite3 +7 -1
  12. data/gemfiles/rails-edge/Gemfile.mysql2 +7 -1
  13. data/gemfiles/rails-edge/Gemfile.postgresql +7 -1
  14. data/gemfiles/rails-edge/Gemfile.sqlite3 +7 -1
  15. data/lib/schema_plus/active_record/column_options_handler.rb +2 -2
  16. data/lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb +124 -57
  17. data/lib/schema_plus/active_record/connection_adapters/foreign_key_definition.rb +9 -2
  18. data/lib/schema_plus/active_record/connection_adapters/mysql_adapter.rb +30 -10
  19. data/lib/schema_plus/active_record/connection_adapters/postgresql_adapter.rb +55 -30
  20. data/lib/schema_plus/active_record/connection_adapters/schema_statements.rb +1 -0
  21. data/lib/schema_plus/active_record/connection_adapters/sqlite3_adapter.rb +10 -7
  22. data/lib/schema_plus/active_record/connection_adapters/table_definition.rb +7 -16
  23. data/lib/schema_plus/active_record/migration/command_recorder.rb +88 -0
  24. data/lib/schema_plus/active_record/schema_dumper.rb +1 -1
  25. data/lib/schema_plus/version.rb +1 -1
  26. data/lib/schema_plus.rb +10 -1
  27. data/runspecs +24 -5
  28. data/spec/column_definition_spec.rb +69 -9
  29. data/spec/index_definition_spec.rb +25 -0
  30. data/spec/index_spec.rb +1 -1
  31. data/spec/migration_spec.rb +76 -11
  32. data/spec/schema_dumper_spec.rb +19 -5
  33. metadata +3 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 57e14aaa2266c620a64f9807c8eda09e72d7f87a
4
- data.tar.gz: a2a284774dd0bd02b0ff0c21421a79278e93813b
3
+ metadata.gz: f36351daeeb9863e7b0344d565b2f67125ed9cea
4
+ data.tar.gz: cb88da4066f4db2f2dfb35f018cc38d82cf6aebc
5
5
  SHA512:
6
- metadata.gz: 51859b083b8f9e245733efad553563b7dd53d569705f70b8fe371c95987b90775b6efde32f033dea70232d629345c6128e5aaf1d5f7b8b1494036286f3c12f4e
7
- data.tar.gz: 9818a2241a8d90f4c5898af00ddb37a34c33011518b70c771533fec90ef63d9d8042ce9ab8850bfd59db45658813f1d118ac4f529396c40336c3be90ead10813
6
+ metadata.gz: f7f2ab813dcf8bd3c02c780337fefc2ae2c5cd793dee59b1cecc76d1706749918bf534685d3d53b7c31bce4989b56e906d292ff1c254f26e9f80d56ac450aca3
7
+ data.tar.gz: 79c000eaa5312482df33ec2d09638d93038ba213320172eb6a029a077efbb41164996cc344a8f3325b06d4cb7702a9aaa3153eeba8f65acf9a9e33e2bc80a651
data/.gitignore CHANGED
@@ -13,6 +13,9 @@ tmtags
13
13
  ## VIM
14
14
  .*.sw?
15
15
 
16
+ ## RubyMine
17
+ /.idea/
18
+
16
19
  ## PROJECT::GENERAL
17
20
  coverage
18
21
  rdoc
data/.travis.yml CHANGED
@@ -1,6 +1,7 @@
1
1
  rvm:
2
2
  - 1.9.3
3
3
  - 2.0.0
4
+ - jruby
4
5
  gemfile:
5
6
  - gemfiles/rails-3.2/Gemfile.postgresql
6
7
  - gemfiles/rails-3.2/Gemfile.sqlite3
@@ -26,3 +27,31 @@ matrix:
26
27
  - gemfile: gemfiles/rails-edge/Gemfile.postgresql
27
28
  - gemfile: gemfiles/rails-edge/Gemfile.sqlite3
28
29
  - gemfile: gemfiles/rails-edge/Gemfile.mysql2
30
+ exclude:
31
+ - rvm: jruby
32
+ gemfile: gemfiles/rails-3.2/Gemfile.sqlite3
33
+ env: 'POSTGRES_DB_USER=postgres MYSQL_DB_USER=""'
34
+ - rvm: jruby
35
+ gemfile: gemfiles/rails-3.2/Gemfile.mysql
36
+ env: 'POSTGRES_DB_USER=postgres MYSQL_DB_USER=""'
37
+ - rvm: jruby
38
+ gemfile: gemfiles/rails-3.2/Gemfile.mysql2
39
+ env: 'POSTGRES_DB_USER=postgres MYSQL_DB_USER=""'
40
+ - rvm: jruby
41
+ gemfile: gemfiles/rails-4.0/Gemfile.postgresql
42
+ env: 'POSTGRES_DB_USER=postgres MYSQL_DB_USER=""'
43
+ - rvm: jruby
44
+ gemfile: gemfiles/rails-4.0/Gemfile.sqlite3
45
+ env: 'POSTGRES_DB_USER=postgres MYSQL_DB_USER=""'
46
+ - rvm: jruby
47
+ gemfile: gemfiles/rails-4.0/Gemfile.mysql2
48
+ env: 'POSTGRES_DB_USER=postgres MYSQL_DB_USER=""'
49
+ - rvm: jruby
50
+ gemfile: gemfiles/rails-edge/Gemfile.postgresql
51
+ env: 'POSTGRES_DB_USER=postgres MYSQL_DB_USER=""'
52
+ - rvm: jruby
53
+ gemfile: gemfiles/rails-edge/Gemfile.sqlite3
54
+ env: 'POSTGRES_DB_USER=postgres MYSQL_DB_USER=""'
55
+ - rvm: jruby
56
+ gemfile: gemfiles/rails-edge/Gemfile.mysql2
57
+ env: 'POSTGRES_DB_USER=postgres MYSQL_DB_USER=""'
data/README.md CHANGED
@@ -22,6 +22,10 @@ SchemaPlus supports all combinations of:
22
22
  3.2), or SQLite3 (using sqlite3 >= 3.7.7 which has foreign key support)
23
23
  * MRI Ruby 1.9.3 or 2.0.0
24
24
 
25
+ And also supports:
26
+
27
+ * jruby with Rails 3.2 and PostgreSQL
28
+
25
29
 
26
30
  Note: As of version 1.0.0, SchemaPlus no longer supports Rails 2.3, 3.0 and
27
31
  3.1, and also no longer supports MRI Ruby 1.8.7; the last version
@@ -118,6 +122,8 @@ SchemaPlus also tidies some index-related behavior:
118
122
  * If you rename a table, indexes named using rails' automatic naming
119
123
  convention will be renamed correspondingly.
120
124
 
125
+ * `remove_index` now accepts an `:if_exists` option to prevent errors from attempting to remove non-existent indexes.
126
+
121
127
 
122
128
  ### Foreign Key Constraints
123
129
 
@@ -290,6 +296,19 @@ of foreign key constraints, you can re-enable it:
290
296
 
291
297
  ## Release notes:
292
298
 
299
+ ### Master branch (to be released)
300
+
301
+ * (nothing new yet)
302
+
303
+ ### 1.3.0
304
+
305
+ * Added :if_exists option for remove_index
306
+ * Initial jruby support (rails 3.2, postgresql), due to efforts of [@donv](https://github.com/donv)
307
+ * Preliminatry groundwork for rails 4.1, due to efforts of [@tovodeverett](https://github.com/tovodeverett)
308
+ * Bug fix for change_table
309
+ * Bug fix for schema_dump postgresql non-btree indexes
310
+ * Bug fix regarding expressions that cast non-string columns to strings in a lower()
311
+
293
312
  ### 1.2.0
294
313
  * Now works with rails 4, due to efforts of [@tovodeverett](https://github.com/tovodeverett)
295
314
  * Test against MRI ruby 2.0.0, no longer test against 1.9.2
@@ -1,4 +1,10 @@
1
1
  require "pathname"
2
2
  eval(Pathname.new(__FILE__).dirname.join("Gemfile.base").read, binding)
3
3
 
4
- gem "mysql", "~> 2.8.1"
4
+ platform :ruby do
5
+ gem "mysql", "~> 2.8.1"
6
+ end
7
+
8
+ platform :jruby do
9
+ gem 'activerecord-jdbcmysql-adapter'
10
+ end
@@ -1,4 +1,10 @@
1
1
  require "pathname"
2
2
  eval(Pathname.new(__FILE__).dirname.join("Gemfile.base").read, binding)
3
3
 
4
- gem "mysql2"
4
+ platform :ruby do
5
+ gem "mysql2"
6
+ end
7
+
8
+ platform :jruby do
9
+ gem 'activerecord-jdbcmysql-adapter'
10
+ end
@@ -1,4 +1,10 @@
1
1
  require "pathname"
2
2
  eval(Pathname.new(__FILE__).dirname.join("Gemfile.base").read, binding)
3
3
 
4
- gem "pg"
4
+ platform :ruby do
5
+ gem "pg"
6
+ end
7
+
8
+ platform :jruby do
9
+ gem 'activerecord-jdbcpostgresql-adapter'
10
+ end
@@ -1,4 +1,10 @@
1
1
  require "pathname"
2
2
  eval(Pathname.new(__FILE__).dirname.join("Gemfile.base").read, binding)
3
3
 
4
- gem "sqlite3"
4
+ platform :ruby do
5
+ gem "sqlite3"
6
+ end
7
+
8
+ platform :jruby do
9
+ gem 'activerecord-jdbcsqlite3-adapter', '>=1.3.0.beta2'
10
+ end
@@ -1,4 +1,10 @@
1
1
  require "pathname"
2
2
  eval(Pathname.new(__FILE__).dirname.join("Gemfile.base").read, binding)
3
3
 
4
- gem "mysql2"
4
+ platform :ruby do
5
+ gem "mysql2"
6
+ end
7
+
8
+ platform :jruby do
9
+ gem 'activerecord-jdbcmysql-adapter'
10
+ end
@@ -1,4 +1,10 @@
1
1
  require "pathname"
2
2
  eval(Pathname.new(__FILE__).dirname.join("Gemfile.base").read, binding)
3
3
 
4
- gem "pg"
4
+ platform :ruby do
5
+ gem "pg"
6
+ end
7
+
8
+ platform :jruby do
9
+ gem 'activerecord-jdbcpostgresql-adapter'
10
+ end
@@ -1,4 +1,10 @@
1
1
  require "pathname"
2
2
  eval(Pathname.new(__FILE__).dirname.join("Gemfile.base").read, binding)
3
3
 
4
- gem "sqlite3"
4
+ platform :ruby do
5
+ gem "sqlite3"
6
+ end
7
+
8
+ platform :jruby do
9
+ gem 'activerecord-jdbcsqlite3-adapter', '>=1.3.0.beta2'
10
+ end
@@ -1,4 +1,10 @@
1
1
  require "pathname"
2
2
  eval(Pathname.new(__FILE__).dirname.join("Gemfile.base").read, binding)
3
3
 
4
- gem "mysql2"
4
+ platform :ruby do
5
+ gem "mysql2"
6
+ end
7
+
8
+ platform :jruby do
9
+ gem 'activerecord-jdbcmysql-adapter'
10
+ end
@@ -1,4 +1,10 @@
1
1
  require "pathname"
2
2
  eval(Pathname.new(__FILE__).dirname.join("Gemfile.base").read, binding)
3
3
 
4
- gem "pg"
4
+ platform :ruby do
5
+ gem "pg"
6
+ end
7
+
8
+ platform :jruby do
9
+ gem 'activerecord-jdbcpostgresql-adapter'
10
+ end
@@ -1,4 +1,10 @@
1
1
  require "pathname"
2
2
  eval(Pathname.new(__FILE__).dirname.join("Gemfile.base").read, binding)
3
3
 
4
- gem "sqlite3"
4
+ platform :ruby do
5
+ gem "sqlite3"
6
+ end
7
+
8
+ platform :jruby do
9
+ gem 'activerecord-jdbcsqlite3-adapter', '>=1.3.0.beta2'
10
+ end
@@ -73,7 +73,7 @@ module SchemaPlus::ActiveRecord
73
73
  def remove_foreign_key_if_exists(table_name, column_name) #:nodoc:
74
74
  foreign_keys = ActiveRecord::Base.connection.foreign_keys(table_name.to_s) rescue [] # no fks if table_name doesn't exist
75
75
  fk = foreign_keys.detect { |fk| fk.table_name == table_name.to_s && fk.column_names == Array(column_name).collect(&:to_s) }
76
- remove_foreign_key(table_name, fk.name) if fk
76
+ remove_foreign_key(table_name, fk.column_names, fk.references_table_name, fk.references_column_names) if fk
77
77
  end
78
78
 
79
79
 
@@ -86,7 +86,7 @@ module SchemaPlus::ActiveRecord
86
86
 
87
87
  def remove_auto_index_if_exists(table_name, column_name)
88
88
  name = auto_index_name(table_name, column_name)
89
- remove_index(table_name, :name => name) if index_exists?(table_name, column_name, :name => name)
89
+ remove_index(table_name, :name => name, :column => column_name, :if_exists => true)
90
90
  end
91
91
 
92
92
  def auto_index_name(table_name, column_name)
@@ -13,6 +13,7 @@ module SchemaPlus
13
13
  module AbstractAdapter
14
14
  def self.included(base) #:nodoc:
15
15
  base.alias_method_chain :initialize, :schema_plus
16
+ base.alias_method_chain :remove_index, :schema_plus
16
17
  end
17
18
 
18
19
  def initialize_with_schema_plus(*args) #:nodoc:
@@ -31,6 +32,13 @@ module SchemaPlus
31
32
  # for this.
32
33
  adapter_module = SchemaPlus::ActiveRecord::ConnectionAdapters.const_get(adapter)
33
34
  self.class.send(:include, adapter_module) unless self.class.include?(adapter_module)
35
+
36
+ if "#{::ActiveRecord::VERSION::MAJOR}.#{::ActiveRecord::VERSION::MINOR}".to_r >= "4.1".to_r
37
+ self.class.const_get(:SchemaCreation).send(:include, adapter_module.const_get(:AddColumnOptions))
38
+ else
39
+ self.class.send(:include, adapter_module.const_get(:AddColumnOptions))
40
+ end
41
+
34
42
  extend(SchemaPlus::ActiveRecord::ForeignKeys)
35
43
  end
36
44
 
@@ -57,17 +65,56 @@ module SchemaPlus
57
65
  # it's created. If you're using Sqlite3, this method will raise an
58
66
  # error.)
59
67
  def add_foreign_key(table_name, column_names, references_table_name, references_column_names, options = {})
60
- foreign_key = ForeignKeyDefinition.new(options[:name] || ForeignKeyDefinition.default_name(table_name, column_names), table_name, column_names, ::ActiveRecord::Migrator.proper_table_name(references_table_name), references_column_names, options[:on_update], options[:on_delete], options[:deferrable])
61
- execute "ALTER TABLE #{quote_table_name(table_name)} ADD #{foreign_key.to_sql}"
68
+ foreign_key_sql = add_foreign_key_sql(table_name, column_names, references_table_name, references_column_names, options)
69
+ execute "ALTER TABLE #{quote_table_name(table_name)} #{foreign_key_sql}"
70
+ end
71
+
72
+ # called directly by AT's bulk_change_table, for migration
73
+ # change_table :name, :bulk => true { ... }
74
+ def add_foreign_key_sql(table_name, column_names, references_table_name, references_column_names, options = {}) #:nodoc:
75
+ foreign_key = _build_foreign_key(table_name, column_names, references_table_name, references_column_names, options)
76
+ "ADD #{foreign_key.to_sql}"
77
+ end
78
+
79
+ def _build_foreign_key(table_name, column_names, references_table_name, references_column_names, options = {}) #:nodoc:
80
+ ForeignKeyDefinition.new(options[:name] || ForeignKeyDefinition.default_name(table_name, column_names), table_name, column_names, ::ActiveRecord::Migrator.proper_table_name(references_table_name), references_column_names, options[:on_update], options[:on_delete], options[:deferrable])
62
81
  end
63
82
 
64
83
  # Remove a foreign key constraint
65
84
  #
85
+ # Arguments are the same as for add_foreign_key, or by name:
86
+ #
87
+ # remove_foreign_key table_name, column_names, references_table_name, references_column_names
88
+ # remove_foreign_key name: constraint_name
89
+ #
66
90
  # (NOTE: Sqlite3 does not support altering a table to remove
67
91
  # foreign-key constraints. If you're using Sqlite3, this method will
68
92
  # raise an error.)
69
- def remove_foreign_key(table_name, foreign_key_name)
70
- execute "ALTER TABLE #{quote_table_name(table_name)} DROP CONSTRAINT #{foreign_key_name}"
93
+ def remove_foreign_key(table_name, *args)
94
+ case sql = remove_foreign_key_sql(table_name, *args)
95
+ when String then execute "ALTER TABLE #{quote_table_name(table_name)} #{sql}"
96
+ end
97
+ end
98
+
99
+ def remove_foreign_key_sql(table_name, *args)
100
+ column_names, references_table_name, references_column_names, options = args
101
+ options ||= {}
102
+ foreign_key_name = case
103
+ when args.length == 1
104
+ case args[0]
105
+ when Hash then args[0][:name]
106
+ else args[0]
107
+ end
108
+ else
109
+ test_fk = _build_foreign_key(table_name, column_names, references_table_name, references_column_names, options)
110
+ if foreign_keys(table_name).detect { |fk| fk == test_fk }
111
+ test_fk.name
112
+ else
113
+ raise "SchemaPlus: no foreign key constraint found on #{table_name.inspect} matching #{args.inspect}" unless options[:if_exists]
114
+ nil
115
+ end
116
+ end
117
+ foreign_key_name ? "DROP CONSTRAINT #{foreign_key_name}" : [] # hack -- return empty array rather than nil, so that result will disappear when caller flattens but doesn't compact
71
118
  end
72
119
 
73
120
  # Extends rails' drop_table to include these options:
@@ -82,6 +129,14 @@ module SchemaPlus
82
129
  execute sql
83
130
  end
84
131
 
132
+ # Extends rails' remove_index to include this options:
133
+ # :if_exists
134
+ def remove_index_with_schema_plus(table_name, options={})
135
+ return if options.delete(:if_exists) and not index_name_exists?(table_name, options[:name] || index_name(table_name, options), false)
136
+ options.delete(:column) if options[:name] and ::ActiveRecord::VERSION::MAJOR < 4
137
+ remove_index_without_schema_plus(table_name, options)
138
+ end
139
+
85
140
  # called from individual adpaters, after renaming table from old
86
141
  # name to
87
142
  def rename_indexes_and_foreign_keys(oldname, newname) #:nodoc:
@@ -113,26 +168,73 @@ module SchemaPlus
113
168
  false
114
169
  end
115
170
 
116
- def add_column_options!(sql, options)
117
- if options_include_default?(options)
118
- default = options[:default]
119
- if default.is_a? Hash
120
- value = default[:value]
121
- expr = sql_for_function(default[:expr]) || default[:expr] if default[:expr]
122
- else
123
- value = default
124
- expr = sql_for_function(default)
125
- end
126
- if expr
127
- raise ArgumentError, "Invalid default expression" unless default_expr_valid?(expr)
128
- sql << " DEFAULT #{expr}"
171
+ module AddColumnOptions
172
+ def self.included(base) #:nodoc:
173
+ base.alias_method_chain :add_column_options!, :schema_plus
174
+ end
175
+
176
+ def add_column_options_with_schema_plus!(sql, options)
177
+ if options_include_default?(options)
178
+ default = options[:default]
179
+
180
+ if default.is_a? Hash
181
+ value = default[:value]
182
+ expr = sql_for_function(default[:expr]) || default[:expr] if default[:expr]
183
+ else
184
+ value = default
185
+ expr = sql_for_function(default)
186
+ end
187
+
188
+ if expr
189
+ raise ArgumentError, "Invalid default expression" unless default_expr_valid?(expr)
190
+ sql << " DEFAULT #{expr}"
191
+ # must explicitly check for :null to allow change_column to work on migrations
192
+ if options[:null] == false
193
+ sql << " NOT NULL"
194
+ end
195
+ else
196
+ add_column_options_without_schema_plus!(sql, options.merge(default: value))
197
+ end
129
198
  else
130
- sql << " DEFAULT #{quote(value, options[:column])}" unless value.nil?
199
+ add_column_options_without_schema_plus!(sql, options)
131
200
  end
132
201
  end
133
- # must explicitly check for :null to allow change_column to work on migrations
134
- if options[:null] == false
135
- sql << " NOT NULL"
202
+
203
+ #####################################################################
204
+ #
205
+ # The functions below here are abstract; each subclass should
206
+ # define them all. Defining them here only for reference.
207
+
208
+ # (abstract) Return true if the passed expression can be used as a column
209
+ # default value. (For most databases the specific expression
210
+ # doesn't matter, and the adapter's function would return a
211
+ # constant true if default expressions are supported or false if
212
+ # they're not.)
213
+ def default_expr_valid?(expr) raise "Internal Error: Connection adapter didn't override abstract function"; end
214
+
215
+ # (abstract) Return SQL definition for a given canonical function_name symbol.
216
+ # Currently, the only function to support is :now, which should
217
+ # return a DATETIME object for the current time.
218
+ def sql_for_function(function_name) raise "Internal Error: Connection adapter didn't override abstract function"; end
219
+ end
220
+
221
+ module VisitTableDefinition
222
+ def self.included(base) #:nodoc:
223
+ base.alias_method_chain :visit_TableDefinition, :schema_plus
224
+ end
225
+
226
+ def visit_TableDefinition_with_schema_plus(o) #:nodoc:
227
+ create_sql = visit_TableDefinition_without_schema_plus(o)
228
+ last_chunk = ") #{o.options}"
229
+
230
+ unless create_sql.end_with?(last_chunk)
231
+ raise "Internal Error: Can't find '#{last_chunk}' at end of '#{create_sql}' - Rails internals have changed!"
232
+ end
233
+
234
+ unless o.foreign_keys.empty?
235
+ create_sql[create_sql.size - last_chunk.size, 0] = ', ' + o.foreign_keys.map(&:to_sql) * ', '
236
+ end
237
+ create_sql
136
238
  end
137
239
  end
138
240
 
@@ -141,7 +243,7 @@ module SchemaPlus
141
243
  # The functions below here are abstract; each subclass should
142
244
  # define them all. Defining them here only for reference.
143
245
  #
144
-
246
+
145
247
  # (abstract) Returns the names of all views, as an array of strings
146
248
  def views(name = nil) raise "Internal Error: Connection adapter didn't override abstract function"; [] end
147
249
 
@@ -157,41 +259,6 @@ module SchemaPlus
157
259
  # (abstract) Return the ForeignKeyDefinition objects for foreign key
158
260
  # constraints defined on other tables that reference this table
159
261
  def reverse_foreign_keys(table_name, name = nil) raise "Internal Error: Connection adapter didn't override abstract function"; [] end
160
-
161
- # (abstract) Return true if the passed expression can be used as a column
162
- # default value. (For most databases the specific expression
163
- # doesn't matter, and the adapter's function would return a
164
- # constant true if default expressions are supported or false if
165
- # they're not.)
166
- def default_expr_valid?(expr) raise "Internal Error: Connection adapter didn't override abstract function"; end
167
-
168
- # (abstract) Return SQL definition for a given canonical function_name symbol.
169
- # Currently, the only function to support is :now, which should
170
- # return a DATETIME object for the current time.
171
- def sql_for_function(function_name) raise "Internal Error: Connection adapter didn't override abstract function"; end
172
-
173
-
174
- if ::ActiveRecord::VERSION::MAJOR.to_i >= 4
175
- module SchemaCreation
176
- def self.included(base) #:nodoc:
177
- base.alias_method_chain :visit_TableDefinition, :schema_plus
178
- end
179
-
180
- def visit_TableDefinition_with_schema_plus(o) #:nodoc:
181
- create_sql = visit_TableDefinition_without_schema_plus(o)
182
- last_chunk = ") #{o.options}"
183
-
184
- unless create_sql.end_with?(last_chunk)
185
- raise "Internal Error: Can't find '#{last_chunk}' at end of '#{create_sql}' - Rails internals have changed!"
186
- end
187
-
188
- unless o.foreign_keys.empty?
189
- create_sql[create_sql.size - last_chunk.size, 0] = ', ' + o.foreign_keys.map(&:to_sql) * ', '
190
- end
191
- create_sql
192
- end
193
- end
194
- end
195
262
  end
196
263
  end
197
264
  end
@@ -49,9 +49,9 @@ module SchemaPlus
49
49
  def initialize(name, table_name, column_names, references_table_name, references_column_names, on_update = nil, on_delete = nil, deferrable = nil)
50
50
  @name = name
51
51
  @table_name = unquote(table_name)
52
- @column_names = unquote(column_names)
52
+ @column_names = unquote(Array.wrap(column_names))
53
53
  @references_table_name = unquote(references_table_name)
54
- @references_column_names = unquote(references_column_names)
54
+ @references_column_names = unquote(Array.wrap(references_column_names))
55
55
  @on_update = on_update
56
56
  @on_delete = on_delete
57
57
  @deferrable = deferrable
@@ -124,6 +124,13 @@ module SchemaPlus
124
124
  table_name.to_s.gsub(/[.]/, '_')
125
125
  end
126
126
 
127
+ def ==(other) # note equality test ignores :name and options
128
+ [:table_name,
129
+ :column_names,
130
+ :references_table_name,
131
+ :references_column_names
132
+ ].all? { |attr| self.send(attr) == other.send(attr) }
133
+ end
127
134
  end
128
135
  end
129
136
  end
@@ -27,11 +27,15 @@ module SchemaPlus
27
27
  tables_without_schema_plus(name, *args) - views(name)
28
28
  end
29
29
 
30
- def remove_column_with_schema_plus(table_name, column_name)
30
+ def remove_column_with_schema_plus(table_name, column_name, type=nil, options={})
31
31
  foreign_keys(table_name).select { |foreign_key| foreign_key.column_names.include?(column_name.to_s) }.each do |foreign_key|
32
32
  remove_foreign_key(table_name, foreign_key.name)
33
33
  end
34
- remove_column_without_schema_plus(table_name, column_name)
34
+ if ::ActiveRecord::VERSION::MAJOR.to_i >= 4
35
+ remove_column_without_schema_plus(table_name, column_name, type, options)
36
+ else
37
+ remove_column_without_schema_plus(table_name, column_name)
38
+ end
35
39
  end
36
40
 
37
41
  def rename_table_with_schema_plus(oldname, newname)
@@ -59,8 +63,22 @@ module SchemaPlus
59
63
  super
60
64
  end
61
65
 
62
- def remove_foreign_key(table_name, foreign_key_name, options = {})
63
- execute "ALTER TABLE #{quote_table_name(table_name)} DROP FOREIGN KEY #{foreign_key_name}"
66
+ def remove_index_sql(table_name, options)
67
+ return [] if options.delete(:if_exists) and not index_exists?(table_name, options)
68
+ super
69
+ end
70
+
71
+ def remove_foreign_key_sql(table_name, *args)
72
+ case ret = super
73
+ when String then ret.sub(/DROP CONSTRAINT/, 'DROP FOREIGN KEY')
74
+ else ret
75
+ end
76
+ end
77
+
78
+ def remove_foreign_key(table_name, *args)
79
+ case sql = remove_foreign_key_sql(table_name, *args)
80
+ when String then execute "ALTER TABLE #{quote_table_name(table_name)} #{sql}"
81
+ end
64
82
  end
65
83
 
66
84
  def foreign_keys(table_name, name = nil)
@@ -147,13 +165,15 @@ module SchemaPlus
147
165
  sql
148
166
  end
149
167
 
150
- def default_expr_valid?(expr)
151
- false # only the TIMESTAMP column accepts SQL column defaults and rails uses DATETIME
152
- end
168
+ module AddColumnOptions
169
+ def default_expr_valid?(expr)
170
+ false # only the TIMESTAMP column accepts SQL column defaults and rails uses DATETIME
171
+ end
153
172
 
154
- def sql_for_function(function)
155
- case function
156
- when :now then 'CURRENT_TIMESTAMP'
173
+ def sql_for_function(function)
174
+ case function
175
+ when :now then 'CURRENT_TIMESTAMP'
176
+ end
157
177
  end
158
178
  end
159
179