schema_plus 0.4.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/.gitignore +3 -1
  2. data/.travis.yml +6 -9
  3. data/Gemfile +0 -4
  4. data/README.rdoc +168 -70
  5. data/Rakefile +58 -47
  6. data/gemfiles/rails-3.2/Gemfile.base +4 -0
  7. data/gemfiles/rails-3.2/Gemfile.mysql +4 -0
  8. data/gemfiles/rails-3.2/Gemfile.mysql2 +4 -0
  9. data/gemfiles/rails-3.2/Gemfile.postgresql +4 -0
  10. data/gemfiles/rails-3.2/Gemfile.sqlite3 +4 -0
  11. data/lib/schema_plus.rb +2 -0
  12. data/lib/schema_plus/active_record/column_options_handler.rb +73 -32
  13. data/lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb +60 -31
  14. data/lib/schema_plus/active_record/connection_adapters/foreign_key_definition.rb +7 -2
  15. data/lib/schema_plus/active_record/connection_adapters/index_definition.rb +2 -1
  16. data/lib/schema_plus/active_record/connection_adapters/mysql_adapter.rb +19 -1
  17. data/lib/schema_plus/active_record/connection_adapters/postgresql_adapter.rb +68 -17
  18. data/lib/schema_plus/active_record/connection_adapters/sqlite3_adapter.rb +28 -3
  19. data/lib/schema_plus/active_record/connection_adapters/table_definition.rb +27 -1
  20. data/lib/schema_plus/active_record/db_default.rb +19 -0
  21. data/lib/schema_plus/active_record/foreign_keys.rb +40 -32
  22. data/lib/schema_plus/active_record/schema_dumper.rb +7 -3
  23. data/lib/schema_plus/version.rb +1 -1
  24. data/runspecs +5 -8
  25. data/schema_plus.gemspec +2 -5
  26. data/spec/column_definition_spec.rb +18 -1
  27. data/spec/column_spec.rb +39 -2
  28. data/spec/connection_spec.rb +1 -1
  29. data/spec/connections/mysql/connection.rb +1 -1
  30. data/spec/connections/mysql2/connection.rb +1 -1
  31. data/spec/connections/postgresql/connection.rb +1 -1
  32. data/spec/foreign_key_definition_spec.rb +0 -4
  33. data/spec/foreign_key_spec.rb +37 -13
  34. data/spec/index_definition_spec.rb +54 -2
  35. data/spec/index_spec.rb +59 -15
  36. data/spec/migration_spec.rb +336 -85
  37. data/spec/multiple_schemas_spec.rb +127 -0
  38. data/spec/schema_dumper_spec.rb +65 -25
  39. data/spec/schema_spec.rb +16 -18
  40. data/spec/spec_helper.rb +19 -18
  41. data/spec/support/matchers/reference.rb +7 -1
  42. data/spec/views_spec.rb +5 -2
  43. metadata +43 -54
  44. data/gemfiles/Gemfile.rails-2.3 +0 -6
  45. data/gemfiles/Gemfile.rails-2.3.lock +0 -65
  46. data/gemfiles/Gemfile.rails-3.0 +0 -5
  47. data/gemfiles/Gemfile.rails-3.0.lock +0 -113
  48. data/gemfiles/Gemfile.rails-3.1 +0 -5
  49. data/gemfiles/Gemfile.rails-3.1.lock +0 -123
  50. data/gemfiles/Gemfile.rails-3.2 +0 -5
  51. data/gemfiles/Gemfile.rails-3.2.lock +0 -121
  52. data/spec/models/comment.rb +0 -2
  53. data/spec/models/post.rb +0 -2
  54. data/spec/models/user.rb +0 -2
  55. data/spec/rails3_migration_spec.rb +0 -144
data/.gitignore CHANGED
@@ -21,5 +21,7 @@ pkg
21
21
  ## PROJECT::SPECIFIC
22
22
  .rvmrc
23
23
  *.log
24
- *.sqlite3
24
+ spec/*/*/*.sqlite3
25
25
  Gemfile.lock
26
+ gemfiles/*.lock
27
+ gemfiles/**/*.lock
data/.travis.yml CHANGED
@@ -1,18 +1,15 @@
1
1
  rvm:
2
- - 1.8.7
3
2
  - 1.9.2
4
3
  - 1.9.3
5
4
  gemfile:
6
- - gemfiles/Gemfile.rails-2.3
7
- - gemfiles/Gemfile.rails-3.0
8
- - gemfiles/Gemfile.rails-3.1
9
- - gemfiles/Gemfile.rails-3.2
5
+ - gemfiles/rails-3.2/Gemfile.postgresql
6
+ - gemfiles/rails-3.2/Gemfile.sqlite3
7
+ - gemfiles/rails-3.2/Gemfile.mysql
8
+ - gemfiles/rails-3.2/Gemfile.mysql2
10
9
  before_script:
11
- - "mysql -e 'create database schema_plus_unittest;' > /dev/null"
12
- - "psql -c 'create database schema_plus_unittest;' -U postgres > /dev/null"
10
+ - rake create_databases
13
11
  after_script:
14
- - "mysql -e 'drop database schema_plus_unittest;' > /dev/null"
15
- - "psql -c 'drop database schema_plus_unittest;' -U postgres > /dev/null"
12
+ - rake drop_databases
16
13
  env: 'POSTGRES_DB_USER=postgres MYSQL_DB_USER=""'
17
14
  notifications:
18
15
  recipients:
data/Gemfile CHANGED
@@ -1,7 +1,3 @@
1
1
  source "http://rubygems.org"
2
2
 
3
3
  gemspec
4
-
5
- platforms :ruby_19 do
6
- gem "ruby-debug19"
7
- end
data/README.rdoc CHANGED
@@ -1,6 +1,5 @@
1
1
  = SchemaPlus
2
2
 
3
- == Overview
4
3
 
5
4
  SchemaPlus is an ActiveRecord extension that provides enhanced capabilities for schema definition and querying, including: enhanced and more DRY index capabilities, support and automation for foreign key constraints, and support for views.
6
5
 
@@ -8,14 +7,18 @@ For added rails DRYness see also the gems
8
7
  {+schema_associations+}[http://rubygems.org/gems/schema_associations] and
9
8
  {+schema_validations+}[http://rubygems.org/gems/schema_validations]
10
9
 
10
+ {<img src="https://secure.travis-ci.org/lomba/schema_plus.png"/>}[http://travis-ci.org/lomba/schema_plus]
11
+ {<img src="https://gemnasium.com/lomba/schema_plus.png" alt="Dependency Status" />}[https://gemnasium.com/lomba/schema_plus]
12
+
11
13
  == Compatibility
12
14
 
13
15
  SchemaPlus supports all combinations of:
14
- * rails 2.3, 3.0, or 3.1, or 3.2
15
- * MRI ruby 1.8.7, 1.9.2 or 1.9.3
16
+ * rails 3.2
16
17
  * PostgreSQL, MySQL (using mysql or mysql2 gem), or SQLite3 (using sqlite3 3.7.7 which has foreign key support)
18
+ * MRI ruby 1.9.2 or 1.9.3
17
19
 
18
- Support for rails 2.3 will likely be dropped eventually.
20
+ Note: As of version 1.0.0, SchemaPlus no longer supports rails 2.3, 3.0 and 3.1 and ruby 1.8.7. The last version
21
+ to support them was 0.4.1.
19
22
 
20
23
  == Installation
21
24
 
@@ -45,15 +48,15 @@ With standard rails migrations, you specify indexes separately from the table de
45
48
  add_index :parts, :name # index repeats table and column names and is defined separately
46
49
  add_index :parts, :product_code, :unique => true
47
50
 
48
- But with SchemaPlus you can specify your indexes when you define each column:
51
+ But with SchemaPlus you can specify your indexes when you define each column, with options as desired
49
52
 
50
53
  # More DRY way...
51
54
  create_table :parts do |t|
52
55
  t.string :name, :index => true
53
- t.string :product_code, :index => :unique
56
+ t.string :product_code, :index => { :unique => true }
54
57
  end
55
58
 
56
- Options can be provided index using a hash, for example:
59
+ The options hash can include an index name:
57
60
 
58
61
  t.string :product_code, :index => { :unique => true, :name => "my_index_name" }
59
62
 
@@ -66,9 +69,45 @@ You can also create multi-column indexes, for example:
66
69
  t.string :area_code
67
70
  t.string :local_number :index => { :with => [:country_code, :area_code], :unique => true }
68
71
 
69
- If you're using Postgresql, SchemaPlus provides support for conditions, expressions, index methods, and case-insensitive indexes; see doc at SchemaPlus::ActiveRecord::ConnectionAdapters::PostgresqlAdapter and SchemaPlus::ActiveRecord::ConnectionAdapters::IndexDefinition
72
+ And you can specify index orders:
73
+
74
+ t.string :first_name
75
+ t.string :last_name, :index => { :with => :first_name, :order => {:first_name => :desc, :last_name => :asc}}
76
+
77
+ As a convenient shorthand, the :unique option can be specified as
78
+
79
+ t.string :product_code, :index => :unique
80
+
81
+ which is equivalent to
82
+
83
+ t.string :product_code, :index => { :unique => true }
84
+
85
+ If you're using Postgresql, SchemaPlus provides support for conditions, expressions, index methods, and case-insensitive indexes:
86
+
87
+ t.string :last_name, :index => { :conditions => 'deleted_at IS NULL' }
88
+ t.string :last_name, :index => { :expression => 'upper(last_name)' }
89
+ t.string :last_name, :index => { :kind => 'hash' }
90
+ t.string :last_name, :index => { :case_sensitive => false } # shorthand for :expression => 'lower(last_name)'
91
+
92
+ These features are available also in ActiveRecord::Migration.add_index. See
93
+ doc at SchemaPlus::ActiveRecord::ConnectionAdapters::PostgresqlAdapter and
94
+ SchemaPlus::ActiveRecord::ConnectionAdapters::IndexDefinition
95
+
96
+ When you query column information using ActiveRecord::Base#columns, SchemaPlus
97
+ analogously provides index information relevant to each column: which indexes
98
+ reference the column, whether the column must be unique, etc. See doc at
99
+ SchemaPlus::ActiveRecord::ConnectionAdapters::Column
100
+
101
+ SchemaPlus also tidies some index-related behavior:
102
+
103
+ * Rails' various db adapters have inconsistent behavior regarding an
104
+ attempt to create a duplicate index: some quietly ignore the attempt,
105
+ some raise an error. SchemaPlus regularizes the behavor to ignore the
106
+ attempt for all db adapters.
107
+
108
+ * If you rename a table, indexes named using rails' automatic naming
109
+ convention will be renamed correspondingly.
70
110
 
71
- And when you query column information using ActiveRecord::Base#columns, SchemaPlus analogously provides index information relevant to each column: which indexes reference the column, whether the column must be unique, etc. See doc at SchemaPlus::ActiveRecord::ConnectionAdapters::Column
72
111
 
73
112
  === Foreign Key Constraints
74
113
 
@@ -77,29 +116,41 @@ common convention that you name a column with suffix +_id+ to indicate that
77
116
  it's a foreign key, SchemaPlus automatically defines the appropriate
78
117
  constraint.
79
118
 
80
- You can explicitly specify foreign key constraints, or override the
81
- automatic ones, using the +:references+ option to specify the table
82
- name (and optionally that table's key column name, if it's not +id+).
119
+ SchemaPlus also creates foreign key constraints for rails' <tt>t.references</tt>
120
+ or <tt>t.belongs_to</tt>, which take the singular of the referenced table
121
+ name and implicitly create the column suffixed with +_id+.
122
+
123
+ You can explicitly specify whether or not to generate a foreign key
124
+ constraint, and specify or override automatic options, using the
125
+ +:foreign_key+ keyword
83
126
 
84
127
  Here are some examples:
85
128
 
86
129
  t.integer :author_id # automatically references table 'authors', key id
87
130
  t.integer :parent_id # special name parent_id automatically references its own table (for tree nodes)
88
- t.integer :author, :references => :authors # non-conventional column name needs :references for a constraint
89
- t.integer :author_id, :references => :authors # same as automatic behavior
90
- t.integer :author_id, :references => [:authors, :id] # same as automatic behavior
91
- t.integer :author_id, :references => :people # override table name
92
- t.integer :author_id, :references => [:people, :ssn] # override table name and key
93
- t.integer :author_id, :references => nil # don't create a constraint
131
+ t.integer :author_id, :foreign_key => true # same as default automatic behavior
132
+ t.integer :author, :foreign_key => true # non-conventional column name needs to force creation, table name is assumed to be 'authors'
133
+ t.integer :author_id, :foreign_key => false # don't create a constraint
94
134
 
95
- You can also modify the behavior using +:on_delete+, +:on_update+, and +:deferrable+
135
+ t.integer :author_id, :foreign_key => { :references => :authors } # same as automatic behavior
136
+ t.integer :author, :foreign_key => { :reference => :authors} # same default name
137
+ t.integer :author_id, :foreign_key => { :references => [:authors, :id] } # same as automatic behavior
138
+ t.integer :author_id, :foreign_key => { :references => :people } # override table name
139
+ t.integer :author_id, :foreign_key => { :references => [:people, :ssn] } # override table name and key
140
+ t.integer :author_id, :foreign_key => { :references => nil } # don't create a constraint
141
+ t.integer :author_id, :foreign_key => { :name => "my_fk" } # override default generated constraint name
142
+ t.integer :author_id, :foreign_key => { :on_delete => :cascade }
143
+ t.integer :author_id, :foreign_key => { :on_update: => :set_null }
144
+ t.integer :author_id, :foreign_key => { :deferrable => true }
96
145
 
97
- t.integer :author_id, :on_delete => :cascade
146
+ Of course the options can be combined, e.g.
98
147
 
99
- SchemaPlus also creates foreign keys when used rails' <tt>t.references</tt>
100
- or <tt>t.belongs_to</tt>< which take the singular of the referenced table
101
- name and implicitly create the column suffixed with +_id+, and it accepts
102
- the same arguments.
148
+ t.integer :author_id, :foreign_key => { :name => "my_fk", :on_delete => :no_action }
149
+
150
+ As a shorthand, all options except +:name+ can be specified without placing them in a hash, e.g.
151
+
152
+ t.integer :author_id, :on_delete => :cascade
153
+ t.integer :author_id, :references => nil
103
154
 
104
155
  The foreign key behavior can be configured globally (see Config) or per-table (see create_table).
105
156
 
@@ -110,42 +161,62 @@ that reference a given table. See SchemaPlus::ActiveRecord::ConnectionAdapters:
110
161
 
111
162
  === Views
112
163
 
113
- SchemaPlus provides support for creating and dropping views. For example:
164
+ SchemaPlus provides support for creating and dropping views. In a migration, a view can be created using a rails relation or literal sql:
165
+
166
+ create_view :posts_commented_by_staff, Post.joins(:comment => :user).where(:users => {:role => 'staff'}).uniq
167
+ create_view :uncommented_posts, "SELECT * FROM posts LEFT OUTER JOIN comments ON comments.post_id = posts.id WHERE comments.id IS NULL"
168
+
169
+ And can be dropped:
114
170
 
115
- create_view :uncommented_posts, "SELECT * FROM posts LEFT OUTER JOIN comments ON comments.post_id = posts.id WHERE comments.id IS NULL"
171
+ drop_view :posts_commented_by_staff
116
172
  drop_view :uncommented_posts
117
173
 
118
- ActiveRecord works with views the same as with ordinary tables. That is, for the above view you can define
174
+ ActiveRecord works with views the same as with ordinary tables. That is, for the above views you can define
119
175
 
120
- class UncommentedPosts < ActiveRecord::Base
176
+ class PostCommentedByStaff < ActiveRecord::Base
177
+ table_name = "posts_commented_by_staff"
121
178
  end
122
179
 
123
- === Column Defaults
180
+ class UncommentedPost < ActiveRecord::Base
181
+ end
182
+
183
+ === Column Defaults: Expressions
184
+
185
+ SchemaPlus allows defaults to be set using expressions or constant values:
186
+
187
+ t.datetime :seen_at, :default => { :expr => 'NOW()' }
188
+ t.datetime :seen_at, :default => { :value => "2011-12-11 00:00:00" }
189
+
190
+ Note that in MySQL only the TIMESTAMP column data type accepts SQL column
191
+ defaults and Rails uses DATETIME, so expressions can't be used with MySQL.
124
192
 
125
- SchemaPlus allows expressions to be used as column defaults. For example:
193
+ The standard syntax will still work as usual:
194
+
195
+ t.datetime :seen_at, :default => "2011-12-11 00:00:00"
196
+
197
+ Also, as a convenience
126
198
 
127
199
  t.datetime :seen_at, :default => :now
128
200
 
129
- resolves to
201
+ resolves to:
130
202
 
131
- DEFAULT NOW() # PostgreSQL
132
- (DATETIME('now')) # SQLite3
133
- invalid # MySQL
203
+ NOW() # PostgreSQL
204
+ (DATETIME('now')) # SQLite3
205
+ invalid # MySQL
134
206
 
135
- Arbitrary SQL expressions can also be specified by passing a hash with an :expr parameter:
207
+ === Column Defaults: Using
136
208
 
137
- t.datetime :seen_at, :default => { :expr => 'NOW()' }
209
+ SchemaPlus introduces a constant <tt>ActiveRecord::DB_DEFAULT</tt> that you can use to explicitly instruct the database to use the column default value (or expression). For example:
138
210
 
139
- In MySQL only the TIMESTAMP column accepts SQL column defaults and Rails uses DATETIME,
140
- so this is not possible at this time.
211
+ Post.create(:category => ActiveRecord::DB_DEFAULT)
212
+ post.update_attributes(:category => ActiveRecord::DB_DEFAULT)
141
213
 
142
- Standard default values can be specified verbosely:
214
+ (Without <tt>ActiveRecord::DB_DEFAULT</tt>, you can update a value to <tt>NULL</tt> but not to its default value.)
143
215
 
144
- t.datetime :seen_at, :default => { :value => "2011-12-11 00:00:00" }
216
+ Note that after updating, you would need to reload a record to replace <tt>ActiveRecord::DB_DEFAULT</tt> with the value assigned by the database.
145
217
 
146
- But the standard syntax will still work as usual:
218
+ Note also that Sqlite3 does not support <tt>ActiveRecord::DB_DEFAULT</tt>; attempting to use it will raise <tt>ActiveRecord::StatementInvalid</tt>
147
219
 
148
- t.datetime :seen_at, :default => "2011-12-11 00:00:00"
149
220
 
150
221
  === Schema Dump and Load (schema.rb)
151
222
 
@@ -161,9 +232,9 @@ definition statements rather than relying on the auto-creation behavior,
161
232
  for maximum clarity and for independence from global config. And
162
233
  correspondingly, when loading a schema, i.e. with the context of
163
234
  <tt>ActiveRecord::Schema.define</tt>, SchemaPlus ensures that auto creation of
164
- foreign keys is turned off regardless of the global setting. But if for
235
+ foreign key constraints is turned off regardless of the global setting. But if for
165
236
  some reason you are creating your schema.rb file by hand, and would like to
166
- take advantage of auto-creation of foreign keys, you can re-enable it:
237
+ take advantage of auto-creation of foreign key constraints, you can re-enable it:
167
238
 
168
239
  ActiveRecord::Schema.define do
169
240
  SchemaPlus.config.foreign_keys.auto_create = true
@@ -173,27 +244,58 @@ take advantage of auto-creation of foreign keys, you can re-enable it:
173
244
  end
174
245
 
175
246
 
176
- == History
247
+ == Release notes:
248
+
249
+ === master (to be released)
250
+
251
+ * No longer support rails < 3.2 and ruby < 1.9
252
+
253
+ * New feature: specify foreign key constraints using :foreign_key => { ... }, motivated in particular to support :name (suggested by https://github.com/daniele-m)
254
+
255
+ * New feature: create view using ActiveRecord relation
256
+
257
+ * New feature: <tt>ActiveRecord::DB_DEFAULT</tt> (suggested by https://github.com/zaadjis)
258
+
259
+ * New feature: renaming a table renames its indexes and constraints correspondingly.
260
+
261
+ * Bug fix for postgres :kind index attribute (thanks to https://github.com/eugenebolshakov)
177
262
 
178
- * Recent Release notes:
179
- * 0.4.1 - bug fix: don't attempt foreign key creation for t.belongs_to ... :polymorphic => true
180
- * 0.4.0 - add :force for create_view (suggested by greglazarev[https://github.com/greglazarev]). cleanups by betelgeuse[https://github.com/betelgeuse]
181
- * 0.3.4 - bug fix: regression causing :default => false to be ignored
182
- * 0.3.3 - bug fix: properly handle boolean defaults in mysql
183
- * 0.3.2 - bug fix: make sure rake db:schema:load initializes schema_plus
184
- * 0.3.1 - bug fix for PostgreSQL schema dump after change_column_default(... nil)
185
- * 0.3.0 - add :default => expressions (Thanks to Luke Saunders). support rails 3.2 and ruby 1.9.3
186
- * 0.2.1 - suppress duplicate add_indexes. compatibility with rails 3.2.0.rc2
263
+ * Sort fks in dump for stability (thanks to https://github.com/zephyr-dev)
264
+
265
+ * Bug fix: change_column should maintain foreign key constraints even when config.foreign_keys.auto_create is false
266
+
267
+ * Bug fix: quote default expressions in schema dump (thanks to https://github.com/jonleighton)
268
+
269
+ * Bug fix: when removing a foreign key constraint, remove its auto-generated index.
270
+
271
+ * Bug fix: SchemaDumper.ignore_tables needs to support regexps (suggeste by https://github.com/mtalcott)
272
+
273
+ * Bug fix: More robust handling of Postgresql schema_search path (suggested by https://github.com/mtalcott)
274
+
275
+ * Bug fix: Only get index, view, and foreign key information from current schema (thanks to https://github.com/bhavinkamani)
276
+
277
+ === Earlier releases
278
+ * 0.4.1 - Bug fix: don't attempt foreign key creation for t.belongs_to ... :polymorphic => true
279
+ * 0.4.0 - Add :force for create_view (suggested by greglazarev[https://github.com/greglazarev]). cleanups by betelgeuse[https://github.com/betelgeuse]
280
+ * 0.3.4 - Bug fix: regression causing :default => false to be ignored
281
+ * 0.3.3 - Bug fix: properly handle boolean defaults in mysql
282
+ * 0.3.2 - Bug fix: make sure rake db:schema:load initializes schema_plus
283
+ * 0.3.1 - Bug fix for PostgreSQL schema dump after change_column_default(... nil)
284
+ * 0.3.0 - Add :default => expressions (Thanks to Luke Saunders). support rails 3.2 and ruby 1.9.3
285
+ * 0.2.1 - Suppress duplicate add_indexes. compatibility with rails 3.2.0.rc2
286
+
287
+ == History
187
288
 
188
289
  * SchemaPlus is derived from several "Red Hill On Rails" plugins
189
290
  originally created by harukizaemon (https://github.com/harukizaemon)
190
291
  with later contributions from
191
292
  * Michał Łomnicki (https://github.com/mlomnicki)
293
+ * Ronen Barzel (https://github.com/ronen)
192
294
  * François Beausoleil (https://github.com/francois)
193
295
  * Greg Barnett (https://github.com/greg-barnett)
194
- * Ronen Barzel (https://github.com/ronen)
195
296
  * Luke Saunders (https://github.com/lukesaunders)
196
297
 
298
+
197
299
  * SchemaPlus was created in 2011 by Michał Łomnicki and Ronen Barzel
198
300
 
199
301
 
@@ -203,28 +305,24 @@ take advantage of auto-creation of foreign keys, you can re-enable it:
203
305
  SchemaPlus is tested using rspec and rvm, with some hackery to test against
204
306
  multiple versions of rails and ruby and db adapters. To run the tests,
205
307
  after you've forked & cloned: Make sure you have Postgresql and MySQL
206
- running. Create database user "schema_plus" with permissions for database
207
- "schema_plus_unittest". Then:
208
-
308
+ running. You'll need db users with permissions to create and access
309
+ databases (schema_plus_test and schema_plus_test2). Default user is
310
+ 'postgres' for Postgresql and 'schema_plus' for MySQL; you can change them via
311
+ $ export POSTGRES_DB_USER = pgusername
312
+ $ export MYSQL_DB_USER = mysqlusername
313
+ Then:
209
314
  $ cd schema_plus
210
315
  $ bundle install
211
- $ rake postgresql:build_databases
212
- $ rake mysql:build_databases
213
- $ ./runspecs --install # do this once, it runs 'bundle install' for all versions (slow)
316
+ $ rake create_databases
317
+ $ ./runspecs --install # do this once, it runs 'bundle install' for all versions
214
318
  $ ./runspecs # as many times as you like
215
319
 
216
- See <tt>./runspecs --help</tt> for more options. You can also manually pick a specific version of rails and ruby to use, such as:
320
+ See <tt>./runspecs --help</tt> for more options. You can also manually pick a specific version of rails, ruby, and db to use, such as:
217
321
  $ rvm use 1.9.2
218
- $ export BUNDLE_GEMFILE=gemfiles/Gemfile.rails-3.1
322
+ $ export BUNDLE_GEMFILE=gemfiles/rails-3.2/Gemfile.sqlite3
219
323
  $ bundle exec rake spec
220
324
 
221
- And you can run the specs for a specific adapter:
222
- $ rake postgresql:spec # to run postgresql tests only
223
- $ rake mysql:spec # to run mysql tests only
224
- $ rake mysql2:spec # to run mysql2 tests only
225
- $ rake sqlite3:spec # to run sqlite3 tests only
226
-
227
- If you're running ruby 1.9, code coverage results will be in coverage/index.html -- it should be at 100% coverage.
325
+ Code coverage results will be in coverage/index.html -- it should be at 100% coverage if you're running against all databases
228
326
 
229
327
  == License
230
328
 
data/Rakefile CHANGED
@@ -1,70 +1,81 @@
1
1
  require 'bundler'
2
2
  Bundler::GemHelper.install_tasks
3
3
 
4
- require 'rspec/core/rake_task'
5
- %w[postgresql mysql mysql2 sqlite3].each do |adapter|
6
- namespace adapter do
7
- RSpec::Core::RakeTask.new(:spec) do |spec|
8
- spec.rspec_opts = "-Ispec/connections/#{adapter}"
9
- spec.fail_on_error = false
10
- end
11
- end
12
- end
4
+ task :default => :spec
13
5
 
14
- desc 'Run postgresql, mysql2 and sqlite3 tests'
15
- task :spec do
16
- %w[postgresql mysql mysql2 sqlite3].each do |adapter|
6
+ desc 'Run test for adapter whose name is suffix of current Gemfile'
7
+ task :spec do
8
+ gemfile = ENV['BUNDLE_GEMFILE']
9
+ fail "BUNDLE_GEMFILE environment variable not set" unless gemfile
10
+ adapter = File.extname(gemfile).sub(/^[.]/, '')
11
+ fail "BUNDLE_GEMFILE filename does not end with .db adapter name" if adapter.empty?
17
12
  Rake::Task["#{adapter}:spec"].invoke
18
- end
19
13
  end
20
14
 
21
- task :default => :spec
22
-
23
- require 'rake/rdoctask'
15
+ require 'rdoc/task'
24
16
  Rake::RDocTask.new do |rdoc|
25
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
17
+ require File.dirname(__FILE__) + '/lib/schema_plus/version'
26
18
 
27
19
  rdoc.rdoc_dir = 'rdoc'
28
- rdoc.title = "schema_plus #{version}"
20
+ rdoc.title = "schema_plus #{SchemaPlus::VERSION}"
29
21
  rdoc.rdoc_files.include('README*')
30
22
  rdoc.rdoc_files.include('lib/**/*.rb')
31
23
  end
32
24
 
33
- namespace :postgresql do
34
- desc 'Build the PostgreSQL test databases'
35
- task :build_databases do
36
- %x( createdb -E UTF8 schema_plus_unittest )
25
+ require 'rspec/core/rake_task'
26
+ %w[postgresql mysql mysql2 sqlite3].each do |adapter|
27
+ namespace adapter do
28
+ RSpec::Core::RakeTask.new(:spec) do |spec|
29
+ spec.rspec_opts = "-Ispec/connections/#{adapter}"
30
+ spec.fail_on_error = true
31
+ end
37
32
  end
33
+ end
38
34
 
39
- desc 'Drop the PostgreSQL test databases'
40
- task :drop_databases do
41
- %x( dropdb schema_plus_unittest )
35
+ DATABASES = %w[schema_plus_test]
36
+ [
37
+ { namespace: :postgresql, uservar: 'POSTGRES_DB_USER', defaultuser: 'postgres', create: "createdb -U '%{user}' %{dbname}", drop: "dropdb -U '%{user}' %{dbname}" },
38
+ { namespace: :mysql, uservar: 'MYSQL_DB_USER', defaultuser: 'schema_plus', create: "mysqladmin -u '%{user}' create %{dbname}", drop: "mysqladmin -u '%{user}' -f drop %{dbname}" }
39
+ ].each do |db|
40
+ namespace db[:namespace] do
41
+ user = ENV.fetch db[:uservar], db[:defaultuser]
42
+ task :create_databases do
43
+ DATABASES.each do |dbname|
44
+ system(db[:create] % {user: user, dbname: dbname})
45
+ end
46
+ end
47
+ task :drop_databases do
48
+ DATABASES.each do |dbname|
49
+ system(db[:drop] % {user: user, dbname: dbname})
50
+ end
51
+ end
42
52
  end
43
-
44
- desc 'Rebuild the PostgreSQL test databases'
45
- task :rebuild_databases => [:drop_databases, :build_databases]
46
53
  end
47
54
 
48
- task :build_postgresql_databases => 'postgresql:build_databases'
49
- task :drop_postgresql_databases => 'postgresql:drop_databases'
50
- task :rebuild_postgresql_databases => 'postgresql:rebuild_databases'
51
-
52
- MYSQL_DB_USER = ENV.fetch('MYSQL_DB_USER', 'schema_plus')
53
- namespace :mysql do
54
- desc 'Build the MySQL test databases'
55
- task :build_databases do
56
- %x( echo "create DATABASE schema_plus_unittest DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_unicode_ci " | mysql --user=#{MYSQL_DB_USER})
57
- end
55
+ desc 'Run postgresql, mysql, mysql2 and sqlite3 tests'
56
+ task :specs do
57
+ invoke_multiple(%w[postgresql mysql mysql2 sqlite3], "spec")
58
+ end
58
59
 
59
- desc 'Drop the MySQL test databases'
60
- task :drop_databases do
61
- %x( mysqladmin --user=#{MYSQL_DB_USER} -f drop schema_plus_unittest )
62
- end
60
+ desc 'Create test databases'
61
+ task :create_databases do
62
+ invoke_multiple(%w[postgresql mysql], "create_databases")
63
+ end
63
64
 
64
- desc 'Rebuild the MySQL test databases'
65
- task :rebuild_databases => [:drop_databases, :build_databases]
65
+ desc 'Drop test databases'
66
+ task :drop_databases do
67
+ invoke_multiple(%w[postgresql mysql], "drop_databases")
66
68
  end
67
69
 
68
- task :build_mysql_databases => 'mysql:build_databases'
69
- task :drop_mysql_databases => 'mysql:drop_databases'
70
- task :rebuild_mysql_databases => 'mysql:rebuild_databases'
70
+ def invoke_multiple(namespaces, task)
71
+ failed = namespaces.reject { |adapter|
72
+ begin
73
+ Rake::Task["#{adapter}:#{task}"].invoke
74
+ true
75
+ rescue => e
76
+ warn "\n#{e}\n"
77
+ false
78
+ end
79
+ }
80
+ fail "Failure in: #{failed.join(', ')}" if failed.any?
81
+ end