schema_plus 1.1.2 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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: