schema_plus 1.1.2 → 1.2.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 57e14aaa2266c620a64f9807c8eda09e72d7f87a
4
+ data.tar.gz: a2a284774dd0bd02b0ff0c21421a79278e93813b
5
+ SHA512:
6
+ metadata.gz: 51859b083b8f9e245733efad553563b7dd53d569705f70b8fe371c95987b90775b6efde32f033dea70232d629345c6128e5aaf1d5f7b8b1494036286f3c12f4e
7
+ data.tar.gz: 9818a2241a8d90f4c5898af00ddb37a34c33011518b70c771533fec90ef63d9d8042ce9ab8850bfd59db45658813f1d118ac4f529396c40336c3be90ead10813
data/.rspec CHANGED
@@ -1,3 +1,2 @@
1
1
  --colour
2
- --format documentation
3
2
  --tty
data/.travis.yml CHANGED
@@ -1,11 +1,17 @@
1
1
  rvm:
2
- - 1.9.2
3
2
  - 1.9.3
3
+ - 2.0.0
4
4
  gemfile:
5
5
  - gemfiles/rails-3.2/Gemfile.postgresql
6
6
  - gemfiles/rails-3.2/Gemfile.sqlite3
7
7
  - gemfiles/rails-3.2/Gemfile.mysql
8
8
  - gemfiles/rails-3.2/Gemfile.mysql2
9
+ - gemfiles/rails-4.0/Gemfile.postgresql
10
+ - gemfiles/rails-4.0/Gemfile.sqlite3
11
+ - gemfiles/rails-4.0/Gemfile.mysql2
12
+ - gemfiles/rails-edge/Gemfile.postgresql
13
+ - gemfiles/rails-edge/Gemfile.sqlite3
14
+ - gemfiles/rails-edge/Gemfile.mysql2
9
15
  before_script:
10
16
  - rake create_databases
11
17
  after_script:
@@ -15,3 +21,8 @@ notifications:
15
21
  recipients:
16
22
  - michal.lomnicki@gmail.com
17
23
  - ronen@barzel.org
24
+ matrix:
25
+ allow_failures:
26
+ - gemfile: gemfiles/rails-edge/Gemfile.postgresql
27
+ - gemfile: gemfiles/rails-edge/Gemfile.sqlite3
28
+ - gemfile: gemfiles/rails-edge/Gemfile.mysql2
data/README.md CHANGED
@@ -9,19 +9,23 @@ For added rails DRYness see also the gems
9
9
  [schema_associations](http://rubygems.org/gems/schema_associations) and
10
10
  [schema_validations](http://rubygems.org/gems/schema_validations)
11
11
 
12
- [<img src="https://secure.travis-ci.org/lomba/schema_plus.png"/>](http://travis-ci.org/lomba/schema_plus)[<img src="https://gemnasium.com/lomba/schema_plus.png" alt="Dependency Status" />](https://gemnasium.com/lomba/schema_plus)
12
+ [![Gem Version](https://badge.fury.io/rb/schema_plus.png)](http://badge.fury.io/rb/schema_plus)
13
+ [![Build Status](https://secure.travis-ci.org/lomba/schema_plus.png)](http://travis-ci.org/lomba/schema_plus)
14
+ [![Dependency Status](https://gemnasium.com/lomba/schema_plus.png)](https://gemnasium.com/lomba/schema_plus)
13
15
 
14
16
  ## Compatibility
15
17
 
16
18
  SchemaPlus supports all combinations of:
17
- * rails 3.2 (up through 3.2.12)
18
- * PostgreSQL, MySQL (using mysql or mysql2 gem), or SQLite3 (using sqlite3
19
- 3.7.7 which has foreign key support)
20
- * MRI ruby 1.9.2 or 1.9.3
21
19
 
20
+ * Rails 3.2 or Rails 4
21
+ * PostgreSQL, MySQL (using mysql2 gem; mysql gem only supported with Rails
22
+ 3.2), or SQLite3 (using sqlite3 >= 3.7.7 which has foreign key support)
23
+ * MRI Ruby 1.9.3 or 2.0.0
22
24
 
23
- Note: As of version 1.0.0, SchemaPlus no longer supports rails 2.3, 3.0 and
24
- 3.1 and ruby 1.8.7. The last version to support them was 0.4.1.
25
+
26
+ Note: As of version 1.0.0, SchemaPlus no longer supports Rails 2.3, 3.0 and
27
+ 3.1, and also no longer supports MRI Ruby 1.8.7; the last version
28
+ to support them was 0.4.1. As of version 1.2.0, SchemaPlus no longer supports MRI Ruby 1.9.2
25
29
 
26
30
  ## Installation
27
31
 
@@ -40,8 +44,8 @@ Here some examples that show off the high points. For full details see the
40
44
 
41
45
  ### Indexes
42
46
 
43
- With standard rails migrations, you specify indexes separately from the table
44
- definition:
47
+ With standard Rails 3 migrations, you specify indexes separately from the
48
+ table definition:
45
49
 
46
50
  # Standard Rails approach...
47
51
  create_table :parts do |t|
@@ -87,7 +91,7 @@ which is equivalent to
87
91
 
88
92
  t.string :product_code, index: { unique: true }
89
93
 
90
- If you're using Postgresql, SchemaPlus provides support for conditions,
94
+ If you're using PostgreSQL, SchemaPlus provides support for conditions,
91
95
  expressions, index methods, and case-insensitive indexes:
92
96
 
93
97
  t.string :last_name, index: { conditions: 'deleted_at IS NULL' }
@@ -168,6 +172,15 @@ list of foreign key constraints defined for a given table, and
168
172
  that reference a given table. See
169
173
  SchemaPlus::ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.
170
174
 
175
+ #### Foreign Key Issues
176
+
177
+ Foreign keys can cause issues for Rails utilities that delete or load data
178
+ because referential integrity imposes a sequencing requirement that those
179
+ utilities may not take into consideration. Monkey-patching may be required
180
+ to address some of these issues. The Wiki article [Making yaml_db work with
181
+ foreign key constraints in PostgreSQL](https://github.com/lomba/schema_plus/wiki/Making-yaml_db-work-with-foreign-key-constraints-in-PostgreSQL)
182
+ has some information that may be of assistance in resolving these issues.
183
+
171
184
  ### Tables
172
185
 
173
186
  SchemaPlus extends rails' `drop_table` method to accept these options:
@@ -277,6 +290,10 @@ of foreign key constraints, you can re-enable it:
277
290
 
278
291
  ## Release notes:
279
292
 
293
+ ### 1.2.0
294
+ * Now works with rails 4, due to efforts of [@tovodeverett](https://github.com/tovodeverett)
295
+ * Test against MRI ruby 2.0.0, no longer test against 1.9.2
296
+
280
297
  ### 1.1.2
281
298
  * Now works with rails 3.2.13 (fixed railtie initialization)
282
299
 
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec :path => File.expand_path('../../..', __FILE__)
4
+ gem "rails", "~> 4.0.0"
@@ -0,0 +1,4 @@
1
+ require "pathname"
2
+ eval(Pathname.new(__FILE__).dirname.join("Gemfile.base").read, binding)
3
+
4
+ gem "mysql2"
@@ -0,0 +1,4 @@
1
+ require "pathname"
2
+ eval(Pathname.new(__FILE__).dirname.join("Gemfile.base").read, binding)
3
+
4
+ gem "pg"
@@ -0,0 +1,4 @@
1
+ require "pathname"
2
+ eval(Pathname.new(__FILE__).dirname.join("Gemfile.base").read, binding)
3
+
4
+ gem "sqlite3"
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec :path => File.expand_path('../../..', __FILE__)
4
+ gem "rails", ">= 4.0.0", :github => "rails/rails"
@@ -0,0 +1,4 @@
1
+ require "pathname"
2
+ eval(Pathname.new(__FILE__).dirname.join("Gemfile.base").read, binding)
3
+
4
+ gem "mysql2"
@@ -0,0 +1,4 @@
1
+ require "pathname"
2
+ eval(Pathname.new(__FILE__).dirname.join("Gemfile.base").read, binding)
3
+
4
+ gem "pg"
@@ -0,0 +1,4 @@
1
+ require "pathname"
2
+ eval(Pathname.new(__FILE__).dirname.join("Gemfile.base").read, binding)
3
+
4
+ gem "sqlite3"
@@ -31,7 +31,6 @@ module SchemaPlus
31
31
  # for this.
32
32
  adapter_module = SchemaPlus::ActiveRecord::ConnectionAdapters.const_get(adapter)
33
33
  self.class.send(:include, adapter_module) unless self.class.include?(adapter_module)
34
- self.post_initialize if self.respond_to? :post_initialize
35
34
  extend(SchemaPlus::ActiveRecord::ForeignKeys)
36
35
  end
37
36
 
@@ -171,6 +170,28 @@ module SchemaPlus
171
170
  # return a DATETIME object for the current time.
172
171
  def sql_for_function(function_name) raise "Internal Error: Connection adapter didn't override abstract function"; end
173
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
174
195
  end
175
196
  end
176
197
  end
@@ -15,6 +15,12 @@ module SchemaPlus
15
15
  alias_method_chain :rename_table, :schema_plus
16
16
  alias_method_chain :exec_stmt, :schema_plus rescue nil # only defined for mysql not mysql2
17
17
  end
18
+
19
+ if ::ActiveRecord::VERSION::MAJOR.to_i >= 4
20
+ base.class_eval do
21
+ include ::ActiveRecord::ConnectionAdapters::SchemaStatements::AddIndex
22
+ end
23
+ end
18
24
  end
19
25
 
20
26
  def tables_with_schema_plus(name=nil, *args)
@@ -49,7 +49,9 @@ module SchemaPlus
49
49
 
50
50
  def self.included(base) #:nodoc:
51
51
  base.class_eval do
52
- remove_method :indexes
52
+ if ::ActiveRecord::VERSION::MAJOR.to_i < 4
53
+ remove_method :indexes
54
+ end
53
55
  alias_method_chain :rename_table, :schema_plus
54
56
  alias_method_chain :exec_cache, :schema_plus
55
57
  end
@@ -95,7 +97,15 @@ module SchemaPlus
95
97
  option_strings = Hash[column_names.map {|name| [name, '']}]
96
98
  option_strings = add_index_sort_order(option_strings, column_names, options)
97
99
 
98
- 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] }
100
+ if options[:case_sensitive] == false
101
+ caseable_columns = columns(table_name).select { |col| [:string, :text].include?(col.type) }.map(&:name)
102
+ quoted_column_names = column_names.map do |col_name|
103
+ (caseable_columns.include?(col_name.to_s) ? "LOWER(#{quote_column_name(col_name)})" : quote_column_name(col_name)) + option_strings[col_name]
104
+ end
105
+ else
106
+ quoted_column_names = column_names.map { |col_name| quote_column_name(col_name) + option_strings[col_name] }
107
+ end
108
+
99
109
  expression = "(#{quoted_column_names.join(', ')})"
100
110
  expression = "USING #{kind} #{expression}" if kind
101
111
 
@@ -150,8 +160,11 @@ module SchemaPlus
150
160
  # case-insensitive index
151
161
  if expression
152
162
  rexp_lower = %r{\blower\(\(?([^)]+)(\)::text)?\)}
153
- if expression.match /^(#{rexp_lower}(, )?)+$/
154
- column_names = expression.scan(rexp_lower).map(&:first)
163
+ if expression.match /\A#{rexp_lower}(?:, #{rexp_lower})*\z/
164
+ case_insensitive_columns = expression.scan(rexp_lower).map(&:first)
165
+ column_names = index_keys.map do |index_key|
166
+ index_key == '0' ? case_insensitive_columns.shift : columns[index_key]
167
+ end
155
168
  case_sensitive = false
156
169
  end
157
170
  end
@@ -4,7 +4,7 @@ module SchemaPlus::ActiveRecord::ConnectionAdapters
4
4
  def self.included(base) #:nodoc:
5
5
  base.class_eval do
6
6
  alias_method_chain :create_table, :schema_plus
7
- alias_method_chain :add_index, :schema_plus
7
+ include AddIndex
8
8
  end
9
9
  end
10
10
 
@@ -25,38 +25,26 @@ module SchemaPlus::ActiveRecord::ConnectionAdapters
25
25
  # override rails' :force to cascade
26
26
  drop_table(table, if_exists: true, cascade: true) if options.delete(:force)
27
27
 
28
- indexes = []
28
+ if ::ActiveRecord::VERSION::MAJOR.to_i < 4
29
+ indexes = []
30
+ end
29
31
  create_table_without_schema_plus(table, options) do |table_definition|
30
32
  table_definition.schema_plus_config = SchemaPlus.config.merge(config_options)
31
- table_definition.name = table
33
+ if ::ActiveRecord::VERSION::MAJOR.to_i < 4
34
+ table_definition.name = table
35
+ end
32
36
  yield table_definition if block_given?
33
- indexes = table_definition.indexes
37
+ if ::ActiveRecord::VERSION::MAJOR.to_i < 4
38
+ indexes = table_definition.indexes
39
+ end
34
40
  end
35
- indexes.each do |index|
36
- add_index(table, index.columns, index.opts)
41
+ if ::ActiveRecord::VERSION::MAJOR.to_i < 4
42
+ indexes.each do |index|
43
+ add_index(table, index.columns, index.opts)
44
+ end
37
45
  end
38
46
  end
39
47
 
40
- ##
41
- # :method: add_index
42
- #
43
- # SchemaPlus modifies SchemaStatements::add_index so that it ignores
44
- # errors raised about add an index that already exists -- i.e. that has
45
- # the same index name, same columns, and same options -- and writes a
46
- # warning to the log. Some combinations of rails & DB adapter versions
47
- # would log such a warning, others would raise an error; with
48
- # SchemaPlus all versions log the warning and do not raise the error.
49
- #
50
- # (This avoids collisions between SchemaPlus's auto index behavior and
51
- # legacy explicit add_index statements, for platforms that would raise
52
- # an error.)
53
- #
54
- def add_index_with_schema_plus(table, columns, options={})
55
- add_index_without_schema_plus(table, columns, options)
56
- rescue => e
57
- SchemaStatements.add_index_exception_handler(self, table, columns, options, e)
58
- end
59
-
60
48
  def self.add_index_exception_handler(connection, table, columns, options, e) #:nodoc:
61
49
  raise unless e.message.match(/["']([^"']+)["'].*already exists/)
62
50
  name = $1
@@ -66,5 +54,32 @@ module SchemaPlus::ActiveRecord::ConnectionAdapters
66
54
  ::ActiveRecord::Base.logger.warn "[schema_plus] Index name #{name.inspect}' on table #{table.inspect} already exists. Skipping."
67
55
  end
68
56
 
57
+ module AddIndex
58
+ def self.included(base) #:nodoc:
59
+ base.class_eval do
60
+ alias_method_chain :add_index, :schema_plus
61
+ end
62
+ end
63
+
64
+ ##
65
+ # :method: add_index
66
+ #
67
+ # SchemaPlus modifies SchemaStatements::add_index so that it ignores
68
+ # errors raised about add an index that already exists -- i.e. that has
69
+ # the same index name, same columns, and same options -- and writes a
70
+ # warning to the log. Some combinations of rails & DB adapter versions
71
+ # would log such a warning, others would raise an error; with
72
+ # SchemaPlus all versions log the warning and do not raise the error.
73
+ #
74
+ # (This avoids collisions between SchemaPlus's auto index behavior and
75
+ # legacy explicit add_index statements, for platforms that would raise
76
+ # an error.)
77
+ #
78
+ def add_index_with_schema_plus(table, columns, options={})
79
+ add_index_without_schema_plus(table, columns, options)
80
+ rescue => e
81
+ SchemaStatements.add_index_exception_handler(self, table, columns, options, e)
82
+ end
83
+ end
69
84
  end
70
85
  end
@@ -21,7 +21,16 @@ module SchemaPlus
21
21
  alias_method_chain :indexes, :schema_plus
22
22
  alias_method_chain :rename_table, :schema_plus
23
23
  end
24
- ::ActiveRecord::ConnectionAdapters::SQLiteColumn.send(:include, SQLiteColumn) unless ::ActiveRecord::ConnectionAdapters::SQLiteColumn.include?(SQLiteColumn)
24
+ if ::ActiveRecord::VERSION::MAJOR.to_i < 4
25
+ ::ActiveRecord::ConnectionAdapters::SQLiteColumn.send(:include, SQLiteColumn) unless ::ActiveRecord::ConnectionAdapters::SQLiteColumn.include?(SQLiteColumn)
26
+ else
27
+ ::ActiveRecord::ConnectionAdapters::SQLite3Column.send(:include, SQLiteColumn) unless ::ActiveRecord::ConnectionAdapters::SQLite3Column.include?(SQLiteColumn)
28
+ end
29
+ end
30
+
31
+ def initialize(*args)
32
+ super
33
+ execute('PRAGMA FOREIGN_KEYS = ON')
25
34
  end
26
35
 
27
36
  def indexes_with_schema_plus(table_name, name = nil)
@@ -71,10 +80,6 @@ module SchemaPlus
71
80
 
72
81
  protected
73
82
 
74
- def post_initialize
75
- execute('PRAGMA FOREIGN_KEYS = 1')
76
- end
77
-
78
83
  def get_foreign_keys(table_name = nil, name = nil)
79
84
  results = execute(<<-SQL, name)
80
85
  SELECT name, sql FROM sqlite_master
@@ -67,30 +67,43 @@ module SchemaPlus::ActiveRecord::ConnectionAdapters
67
67
  include SchemaPlus::ActiveRecord::ColumnOptionsHandler
68
68
 
69
69
  attr_accessor :schema_plus_config #:nodoc:
70
+ attr_reader :foreign_keys #:nodoc:
70
71
 
71
72
  def self.included(base) #:nodoc:
72
73
  base.class_eval do
73
- attr_accessor :name
74
- attr_accessor :indexes
75
74
  alias_method_chain :initialize, :schema_plus
76
75
  alias_method_chain :column, :schema_plus
77
76
  alias_method_chain :references, :schema_plus
78
77
  alias_method_chain :belongs_to, :schema_plus
79
78
  alias_method_chain :primary_key, :schema_plus
80
- alias_method_chain :to_sql, :schema_plus
79
+
80
+ if ::ActiveRecord::VERSION::MAJOR.to_i < 4
81
+ attr_accessor :name
82
+ attr_accessor :indexes
83
+ alias_method_chain :to_sql, :schema_plus
84
+ end
81
85
  end
82
86
  end
83
-
87
+
84
88
  def initialize_with_schema_plus(*args) #:nodoc:
85
89
  initialize_without_schema_plus(*args)
86
90
  @foreign_keys = []
87
- @indexes = []
91
+ if ::ActiveRecord::VERSION::MAJOR.to_i < 4
92
+ @indexes = []
93
+ end
88
94
  end
89
95
 
90
- def primary_key_with_schema_plus(name, options = {}) #:nodoc:
91
- column(name, :primary_key, options)
96
+ if ::ActiveRecord::VERSION::MAJOR.to_i < 4
97
+ def primary_key_with_schema_plus(name, options = {}) #:nodoc:
98
+ column(name, :primary_key, options)
99
+ end
100
+ else
101
+ def primary_key_with_schema_plus(name, type = :primary_key, options = {}) #:nodoc:
102
+ column(name, type, options.merge(:primary_key => true))
103
+ end
92
104
  end
93
105
 
106
+
94
107
  # need detect :polymorphic at this level, because rails strips it out
95
108
  # before calling #column (twice, once for _id and once for _type)
96
109
  def references_with_schema_plus(*args) #:nodoc:
@@ -122,8 +135,10 @@ module SchemaPlus::ActiveRecord::ConnectionAdapters
122
135
  end
123
136
 
124
137
  # Define an index for the current
125
- def index(column_name, options={})
126
- @indexes << ::ActiveRecord::ConnectionAdapters::IndexDefinition.new(self.name, column_name, options)
138
+ if ::ActiveRecord::VERSION::MAJOR.to_i < 4
139
+ def index(column_name, options={})
140
+ @indexes << ::ActiveRecord::ConnectionAdapters::IndexDefinition.new(self.name, column_name, options)
141
+ end
127
142
  end
128
143
 
129
144
  def foreign_key(column_names, references_table_name, references_column_names, options = {})
@@ -165,7 +180,11 @@ module SchemaPlus::ActiveRecord::ConnectionAdapters
165
180
  # Determines if an indexes is queued to be created. Called from
166
181
  # ColumnOptionsHandler as part of checking whether to auto-create an index
167
182
  def index_exists?(_, column_name, options={})
168
- @indexes.find{|index| index.table == self.name && index.columns == Array.wrap(column_name) && options.all?{|k, v| index.send(k) == v}}
183
+ if ::ActiveRecord::VERSION::MAJOR.to_i < 4
184
+ @indexes.find{|index| index.table == self.name && index.columns == Array.wrap(column_name) && options.all?{|k, v| index.send(k) == v}}
185
+ else
186
+ @indexes.find {|index_column_name, index_options| Array.wrap(index_column_name) == Array.wrap(column_name) && options.all?{|k, v| index_options[k] == v} }
187
+ end
169
188
  end
170
189
 
171
190
 
@@ -1,3 +1,3 @@
1
1
  module SchemaPlus
2
- VERSION = "1.1.2"
2
+ VERSION = "1.2.0"
3
3
  end
data/lib/schema_plus.rb CHANGED
@@ -124,6 +124,10 @@ module SchemaPlus
124
124
  ::ActiveRecord::ConnectionAdapters::IndexDefinition.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::IndexDefinition)
125
125
  ::ActiveRecord::ConnectionAdapters::SchemaStatements.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::SchemaStatements)
126
126
  ::ActiveRecord::ConnectionAdapters::TableDefinition.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::TableDefinition)
127
+
128
+ if ::ActiveRecord::VERSION::MAJOR.to_i >= 4
129
+ ::ActiveRecord::ConnectionAdapters::AbstractAdapter::SchemaCreation.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::AbstractAdapter::SchemaCreation)
130
+ end
127
131
  end
128
132
 
129
133
  def self.insert #:nodoc:
data/runspecs CHANGED
@@ -5,8 +5,8 @@ require 'ostruct'
5
5
  require 'shellwords'
6
6
  require 'tempfile'
7
7
 
8
- RUBY_VERSIONS = %W[1.9.2 1.9.3]
9
- RAILS_VERSIONS = %W[3.2]
8
+ RUBY_VERSIONS = %W[1.9.3 2.0.0]
9
+ RAILS_VERSIONS = %W[3.2 4.0]
10
10
  DB_ADAPTERS = %W[postgresql mysql mysql2 sqlite3]
11
11
 
12
12
  o = OpenStruct.new
@@ -65,10 +65,21 @@ Combo = Struct.new(:ruby, :rails, :db_adapter)
65
65
  combos = o.ruby_versions.product(o.rails_versions, o.db_adapters).map{|product| Combo.new(*product)}.select {|combo|
66
66
  case
67
67
  when combo.rails >= "3.2" && combo.ruby <= "1.8.7" then false # no longer happens, just keeping it as an example
68
+ when combo.rails >= "4" && combo.db_adapter == "mysql" then false
68
69
  else true
69
70
  end
70
71
  }
71
72
 
73
+ def ruby_version_selector(ruby)
74
+ if @use_rvm ||= system("which -s rvm")
75
+ "rvm #{ruby} do"
76
+ else
77
+ @versions ||= `rbenv versions --bare`.split
78
+ version = @versions.select{|v| v.start_with? ruby}.last || abort("no ruby version '#{ruby}' installed in rbenv")
79
+ "RBENV_VERSION=#{version}"
80
+ end
81
+ end
82
+
72
83
 
73
84
  GEMFILES_DIR = File.expand_path('../gemfiles', __FILE__)
74
85
  errs = []
@@ -88,7 +99,7 @@ combos.each_with_index do |combo, n|
88
99
  "bundle exec rake #{db_adapter}:spec"
89
100
  end
90
101
 
91
- command = %Q{BUNDLE_GEMFILE="#{File.join(GEMFILES_DIR, "rails-#{rails}", "Gemfile.#{db_adapter}")}" rvm #{ruby} do #{cmd} #{Shellwords.join(ARGV)}}
102
+ command = %Q{BUNDLE_GEMFILE="#{File.join(GEMFILES_DIR, "rails-#{rails}", "Gemfile.#{db_adapter}")}" #{ruby_version_selector(ruby)} #{cmd} #{Shellwords.join(ARGV)}}
92
103
 
93
104
  puts "\n\n*** ruby version #{ruby} - rails version #{rails} - db adapter: #{db_adapter} [#{n+1} of #{combos.size}]\n\n#{command}"
94
105
 
@@ -29,6 +29,28 @@ describe "Foreign Key" do
29
29
 
30
30
  end
31
31
 
32
+ if ::ActiveRecord::VERSION::MAJOR.to_i >= 4
33
+ context "with modifications to SQL generated by upstream visit_TableDefinition" do
34
+ before(:each) do
35
+ ActiveRecord::Base.connection.class.const_get(:SchemaCreation).any_instance.stub :visit_TableDefinition_without_schema_plus => "this is unexpected"
36
+ end
37
+
38
+ it "raises an exception when attempting to create a table" do
39
+ expect {
40
+ define_schema(:auto_create => true) do
41
+ create_table :users, :force => true do |t|
42
+ t.string :login
43
+ end
44
+ create_table :comments, :force => true do |t|
45
+ t.integer :user_id
46
+ t.foreign_key :user_id, :users, :id
47
+ end
48
+ end
49
+ }.to raise_error(RuntimeError, /Internal Error: Can't find.*Rails internals have changed/)
50
+ end
51
+ end
52
+ end
53
+
32
54
  context "modification" do
33
55
 
34
56
  before(:all) do
@@ -22,6 +22,17 @@ describe "Schema dump" do
22
22
  t.integer :user_id
23
23
  t.integer :first_comment_id
24
24
  t.string :string_no_default
25
+ t.integer :short_id
26
+ t.string :str_short
27
+ t.integer :integer_col
28
+ t.float :float_col
29
+ t.decimal :decimal_col
30
+ t.datetime :datetime_col
31
+ t.timestamp :timestamp_col
32
+ t.time :time_col
33
+ t.date :date_col
34
+ t.binary :binary_col
35
+ t.boolean :boolean_col
25
36
  end
26
37
 
27
38
  create_table :comments, :force => true do |t|
@@ -80,19 +91,19 @@ describe "Schema dump" do
80
91
  if SchemaPlusHelpers.postgresql?
81
92
  it "should dump the default hash expr as now()" do
82
93
  with_additional_column Post, :posted_at, :datetime, :default => :now do
83
- dump_posts.should match(to_regexp(%q{t.datetime "posted_at", :default => \{ :expr => "now()" \}}))
94
+ dump_posts.should match(%r{t\.datetime\s+"posted_at",\s*(?:default:|:default =>)\s*\{\s*(?:expr:|:expr =>)\s*"now\(\)"\s*\}})
84
95
  end
85
96
  end
86
97
 
87
98
  it "should dump the default hash expr as CURRENT_TIMESTAMP" do
88
99
  with_additional_column Post, :posted_at, :datetime, :default => {:expr => 'date \'2001-09-28\''} do
89
- dump_posts.should match(%r{t.datetime "posted_at",\s*:default => '2001-09-28 00:00:00'})
100
+ dump_posts.should match(%r{t\.datetime\s+"posted_at",\s*(?:default:|:default =>)\s*'2001-09-28 00:00:00'})
90
101
  end
91
102
  end
92
103
 
93
104
  it "can dump a complex default expression" do
94
105
  with_additional_column Post, :name, :string, :default => {:expr => 'substring(random()::text from 3 for 6)'} do
95
- dump_posts.should match(%r{t.string\s+"name", :default => { :expr => "\\"substring\\"\(\(random\(\)\)::text, 3, 6\)" }})
106
+ dump_posts.should match(%r{t\.string\s+"name",\s*(?:default:|:default =>)\s*{\s*(?:expr:|:expr =>)\s*"\\"substring\\"\(\(random\(\)\)::text, 3, 6\)"\s*}})
96
107
  end
97
108
  end
98
109
  end
@@ -100,19 +111,19 @@ describe "Schema dump" do
100
111
  if SchemaPlusHelpers.sqlite3?
101
112
  it "should dump the default hash expr as now" do
102
113
  with_additional_column Post, :posted_at, :datetime, :default => :now do
103
- dump_posts.should match(to_regexp(%q{t.datetime "posted_at", :default => \{ :expr => "(DATETIME('now'))" \}}))
114
+ dump_posts.should match(%r{t\.datetime\s+"posted_at",\s*(?:default:|:default =>)\s*\{\s*(?:expr:|:expr =>)\s*"\(DATETIME\('now'\)\)"\s*\}})
104
115
  end
105
116
  end
106
117
 
107
118
  it "should dump the default hash expr string as now" do
108
119
  with_additional_column Post, :posted_at, :datetime, :default => { :expr => "(DATETIME('now'))" } do
109
- dump_posts.should match(to_regexp(%q{t.datetime "posted_at", :default => \{ :expr => "(DATETIME('now'))" \}}))
120
+ dump_posts.should match(%r{t\.datetime\s+"posted_at",\s*(?:default:|:default =>)\s*\{\s*(?:expr:|:expr =>)\s*"\(DATETIME\('now'\)\)"\s*\}})
110
121
  end
111
122
  end
112
123
 
113
124
  it "should dump the default value normally" do
114
125
  with_additional_column Post, :posted_at, :string, :default => "now" do
115
- dump_posts.should match(%r{t.string "posted_at",\s*:default => "now"})
126
+ dump_posts.should match(%r{t\.string\s*"posted_at",\s*(?:default:|:default =>)\s*"now"})
116
127
  end
117
128
  end
118
129
  end
@@ -123,7 +134,7 @@ describe "Schema dump" do
123
134
  ActiveRecord::Migration.suppress_messages do
124
135
  ActiveRecord::Migration.change_column_default :posts, :string_no_default, nil
125
136
  end
126
- dump_posts.should match(%r{t.string\s+"string_no_default"\s*$})
137
+ dump_posts.should match(%r{t\.string\s+"string_no_default"\s*$})
127
138
  end
128
139
 
129
140
  it "should include foreign_key options" do
@@ -168,6 +179,21 @@ describe "Schema dump" do
168
179
  end
169
180
  end
170
181
 
182
+ it "should define case insensitive index with mixed ids and strings" do
183
+ with_index Post, [:user_id, :str_short, :short_id, :body], :case_sensitive => false do
184
+ dump_posts.should match(to_regexp(%q{t.index ["user_id", "str_short", "short_id", "body"], :name => "index_posts_on_user_id_and_str_short_and_short_id_and_body", :case_sensitive => false}))
185
+ end
186
+ end
187
+
188
+ [:integer, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean].each do |col_type|
189
+ col_name = "#{col_type}_col"
190
+ it "should define case insensitive index that includes an #{col_type}" do
191
+ with_index Post, [:user_id, :str_short, col_name, :body], :case_sensitive => false do
192
+ dump_posts.should match(to_regexp(%Q!t.index ["user_id", "str_short", "#{col_name}", "body"], :name => "index_posts_on_user_id_and_str_short_and_#{col_name}_and_body", :case_sensitive => false!))
193
+ end
194
+ end
195
+ end
196
+
171
197
  it "should define conditions" do
172
198
  with_index Post, :user_id, :name => "posts_user_id_index", :conditions => "user_id IS NOT NULL" do
173
199
  dump_posts.should match(to_regexp(%q{t.index ["user_id"], :name => "posts_user_id_index", :conditions => "(user_id IS NOT NULL)"}))
data/spec/spec_helper.rb CHANGED
@@ -1,8 +1,8 @@
1
- if RUBY_VERSION > "1.9"
2
- require 'simplecov'
3
- require 'simplecov-gem-adapter'
4
- SimpleCov.start "gem"
5
- end
1
+ require 'simplecov'
2
+ require 'simplecov-gem-adapter'
3
+ SimpleCov.use_merging true
4
+ SimpleCov.merge_timeout 3600
5
+ SimpleCov.start "gem"
6
6
 
7
7
  $LOAD_PATH.unshift(File.dirname(__FILE__))
8
8
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
@@ -55,4 +55,4 @@ def remove_all_models
55
55
  end
56
56
  end
57
57
 
58
- SimpleCov.command_name ActiveRecord::Base.connection.adapter_name if defined? SimpleCov
58
+ SimpleCov.command_name "[ruby #{RUBY_VERSION} - ActiveRecord #{::ActiveRecord::VERSION::STRING} - #{ActiveRecord::Base.connection.adapter_name}]"
metadata CHANGED
@@ -1,8 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: schema_plus
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.2
5
- prerelease:
4
+ version: 1.2.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Ronen Barzel
@@ -10,105 +9,93 @@ authors:
10
9
  autorequire:
11
10
  bindir: bin
12
11
  cert_chain: []
13
- date: 2013-03-20 00:00:00.000000000 Z
12
+ date: 2013-08-13 00:00:00.000000000 Z
14
13
  dependencies:
15
14
  - !ruby/object:Gem::Dependency
16
15
  name: rails
17
16
  requirement: !ruby/object:Gem::Requirement
18
- none: false
19
17
  requirements:
20
- - - ! '>='
18
+ - - '>='
21
19
  - !ruby/object:Gem::Version
22
20
  version: '3.2'
23
21
  type: :runtime
24
22
  prerelease: false
25
23
  version_requirements: !ruby/object:Gem::Requirement
26
- none: false
27
24
  requirements:
28
- - - ! '>='
25
+ - - '>='
29
26
  - !ruby/object:Gem::Version
30
27
  version: '3.2'
31
28
  - !ruby/object:Gem::Dependency
32
29
  name: valuable
33
30
  requirement: !ruby/object:Gem::Requirement
34
- none: false
35
31
  requirements:
36
- - - ! '>='
32
+ - - '>='
37
33
  - !ruby/object:Gem::Version
38
34
  version: '0'
39
35
  type: :runtime
40
36
  prerelease: false
41
37
  version_requirements: !ruby/object:Gem::Requirement
42
- none: false
43
38
  requirements:
44
- - - ! '>='
39
+ - - '>='
45
40
  - !ruby/object:Gem::Version
46
41
  version: '0'
47
42
  - !ruby/object:Gem::Dependency
48
43
  name: rake
49
44
  requirement: !ruby/object:Gem::Requirement
50
- none: false
51
45
  requirements:
52
- - - ! '>='
46
+ - - '>='
53
47
  - !ruby/object:Gem::Version
54
48
  version: '0'
55
49
  type: :development
56
50
  prerelease: false
57
51
  version_requirements: !ruby/object:Gem::Requirement
58
- none: false
59
52
  requirements:
60
- - - ! '>='
53
+ - - '>='
61
54
  - !ruby/object:Gem::Version
62
55
  version: '0'
63
56
  - !ruby/object:Gem::Dependency
64
57
  name: rspec
65
58
  requirement: !ruby/object:Gem::Requirement
66
- none: false
67
59
  requirements:
68
- - - ! '>='
60
+ - - '>='
69
61
  - !ruby/object:Gem::Version
70
62
  version: '0'
71
63
  type: :development
72
64
  prerelease: false
73
65
  version_requirements: !ruby/object:Gem::Requirement
74
- none: false
75
66
  requirements:
76
- - - ! '>='
67
+ - - '>='
77
68
  - !ruby/object:Gem::Version
78
69
  version: '0'
79
70
  - !ruby/object:Gem::Dependency
80
71
  name: simplecov
81
72
  requirement: !ruby/object:Gem::Requirement
82
- none: false
83
73
  requirements:
84
- - - ! '>='
74
+ - - '>='
85
75
  - !ruby/object:Gem::Version
86
76
  version: '0'
87
77
  type: :development
88
78
  prerelease: false
89
79
  version_requirements: !ruby/object:Gem::Requirement
90
- none: false
91
80
  requirements:
92
- - - ! '>='
81
+ - - '>='
93
82
  - !ruby/object:Gem::Version
94
83
  version: '0'
95
84
  - !ruby/object:Gem::Dependency
96
85
  name: simplecov-gem-adapter
97
86
  requirement: !ruby/object:Gem::Requirement
98
- none: false
99
87
  requirements:
100
- - - ! '>='
88
+ - - '>='
101
89
  - !ruby/object:Gem::Version
102
90
  version: '0'
103
91
  type: :development
104
92
  prerelease: false
105
93
  version_requirements: !ruby/object:Gem::Requirement
106
- none: false
107
94
  requirements:
108
- - - ! '>='
95
+ - - '>='
109
96
  - !ruby/object:Gem::Version
110
97
  version: '0'
111
- description: ! 'SchemaPlus is an ActiveRecord extension that provides enhanced capabilities
98
+ description: 'SchemaPlus is an ActiveRecord extension that provides enhanced capabilities
112
99
  for schema definition and querying, including: enhanced and more DRY index capabilities,
113
100
  support and automation for foreign key constraints, and support for views.'
114
101
  email:
@@ -130,6 +117,14 @@ files:
130
117
  - gemfiles/rails-3.2/Gemfile.mysql2
131
118
  - gemfiles/rails-3.2/Gemfile.postgresql
132
119
  - gemfiles/rails-3.2/Gemfile.sqlite3
120
+ - gemfiles/rails-4.0/Gemfile.base
121
+ - gemfiles/rails-4.0/Gemfile.mysql2
122
+ - gemfiles/rails-4.0/Gemfile.postgresql
123
+ - gemfiles/rails-4.0/Gemfile.sqlite3
124
+ - gemfiles/rails-edge/Gemfile.base
125
+ - gemfiles/rails-edge/Gemfile.mysql2
126
+ - gemfiles/rails-edge/Gemfile.postgresql
127
+ - gemfiles/rails-edge/Gemfile.sqlite3
133
128
  - init.rb
134
129
  - lib/rails/tasks/database.rake
135
130
  - lib/schema_plus.rb
@@ -177,27 +172,26 @@ files:
177
172
  - spec/views_spec.rb
178
173
  homepage: https://github.com/lomba/schema_plus
179
174
  licenses: []
175
+ metadata: {}
180
176
  post_install_message:
181
177
  rdoc_options: []
182
178
  require_paths:
183
179
  - lib
184
180
  required_ruby_version: !ruby/object:Gem::Requirement
185
- none: false
186
181
  requirements:
187
- - - ! '>='
182
+ - - '>='
188
183
  - !ruby/object:Gem::Version
189
184
  version: 1.9.2
190
185
  required_rubygems_version: !ruby/object:Gem::Requirement
191
- none: false
192
186
  requirements:
193
- - - ! '>='
187
+ - - '>='
194
188
  - !ruby/object:Gem::Version
195
189
  version: '0'
196
190
  requirements: []
197
191
  rubyforge_project: schema_plus
198
- rubygems_version: 1.8.25
192
+ rubygems_version: 2.0.3
199
193
  signing_key:
200
- specification_version: 3
194
+ specification_version: 4
201
195
  summary: Enhances ActiveRecord schema mechanism, including more DRY index creation
202
196
  and support for foreign key constraints and views.
203
197
  test_files:
@@ -224,4 +218,3 @@ test_files:
224
218
  - spec/support/matchers/have_index.rb
225
219
  - spec/support/matchers/reference.rb
226
220
  - spec/views_spec.rb
227
- has_rdoc: