schema_plus 1.2.0 → 1.3.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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.travis.yml +29 -0
  4. data/README.md +19 -0
  5. data/gemfiles/rails-3.2/Gemfile.mysql +7 -1
  6. data/gemfiles/rails-3.2/Gemfile.mysql2 +7 -1
  7. data/gemfiles/rails-3.2/Gemfile.postgresql +7 -1
  8. data/gemfiles/rails-3.2/Gemfile.sqlite3 +7 -1
  9. data/gemfiles/rails-4.0/Gemfile.mysql2 +7 -1
  10. data/gemfiles/rails-4.0/Gemfile.postgresql +7 -1
  11. data/gemfiles/rails-4.0/Gemfile.sqlite3 +7 -1
  12. data/gemfiles/rails-edge/Gemfile.mysql2 +7 -1
  13. data/gemfiles/rails-edge/Gemfile.postgresql +7 -1
  14. data/gemfiles/rails-edge/Gemfile.sqlite3 +7 -1
  15. data/lib/schema_plus/active_record/column_options_handler.rb +2 -2
  16. data/lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb +124 -57
  17. data/lib/schema_plus/active_record/connection_adapters/foreign_key_definition.rb +9 -2
  18. data/lib/schema_plus/active_record/connection_adapters/mysql_adapter.rb +30 -10
  19. data/lib/schema_plus/active_record/connection_adapters/postgresql_adapter.rb +55 -30
  20. data/lib/schema_plus/active_record/connection_adapters/schema_statements.rb +1 -0
  21. data/lib/schema_plus/active_record/connection_adapters/sqlite3_adapter.rb +10 -7
  22. data/lib/schema_plus/active_record/connection_adapters/table_definition.rb +7 -16
  23. data/lib/schema_plus/active_record/migration/command_recorder.rb +88 -0
  24. data/lib/schema_plus/active_record/schema_dumper.rb +1 -1
  25. data/lib/schema_plus/version.rb +1 -1
  26. data/lib/schema_plus.rb +10 -1
  27. data/runspecs +24 -5
  28. data/spec/column_definition_spec.rb +69 -9
  29. data/spec/index_definition_spec.rb +25 -0
  30. data/spec/index_spec.rb +1 -1
  31. data/spec/migration_spec.rb +76 -11
  32. data/spec/schema_dumper_spec.rb +19 -5
  33. metadata +3 -2
@@ -6,9 +6,13 @@ module SchemaPlus
6
6
  # Extracts the value from a PostgreSQL column default definition.
7
7
  def self.included(base) #:nodoc:
8
8
  base.extend ClassMethods
9
- base.class_eval do
10
- class << self
11
- alias_method_chain :extract_value_from_default, :schema_plus
9
+ if defined?(JRUBY_VERSION)
10
+ base.alias_method_chain :default_value, :schema_plus
11
+ else
12
+ base.class_eval do
13
+ class << self
14
+ alias_method_chain :extract_value_from_default, :schema_plus
15
+ end
12
16
  end
13
17
  end
14
18
  end
@@ -23,16 +27,22 @@ module SchemaPlus
23
27
  super(name, default, sql_type, null)
24
28
  end
25
29
 
30
+ def default_value_with_schema_plus(default)
31
+ value = default_value_without_schema_plus(default)
32
+ self.class.convert_default_value(default, value)
33
+ end
34
+
26
35
  module ClassMethods
27
36
  def extract_value_from_default_with_schema_plus(default)
28
-
29
-
30
37
  value = extract_value_from_default_without_schema_plus(default)
38
+ convert_default_value(default, value)
39
+ end
31
40
 
32
- # in some cases (e.g. if change_column_default(table, column,
33
- # nil) is used), postgresql will return NULL::xxxxx (rather
34
- # than nil) for a null default -- make sure we treat it as nil,
35
- # not as a function.
41
+ # in some cases (e.g. if change_column_default(table, column,
42
+ # nil) is used), postgresql will return NULL::xxxxx (rather
43
+ # than nil) for a null default -- make sure we treat it as nil,
44
+ # not as a function.
45
+ def convert_default_value(default, value)
36
46
  default = nil if value.nil? && default =~ /\ANULL::(?:character varying|bpchar|text)\z/m
37
47
 
38
48
  if value.nil? && !default.nil?
@@ -49,11 +59,11 @@ module SchemaPlus
49
59
 
50
60
  def self.included(base) #:nodoc:
51
61
  base.class_eval do
52
- if ::ActiveRecord::VERSION::MAJOR.to_i < 4
62
+ if ::ActiveRecord::VERSION::MAJOR.to_i < 4 && !defined?(JRUBY_VERSION)
53
63
  remove_method :indexes
54
64
  end
55
65
  alias_method_chain :rename_table, :schema_plus
56
- alias_method_chain :exec_cache, :schema_plus
66
+ alias_method_chain :exec_cache, :schema_plus unless defined?(JRUBY_VERSION)
57
67
  end
58
68
  ::ActiveRecord::ConnectionAdapters::PostgreSQLColumn.send(:include, PostgreSQLColumn) unless ::ActiveRecord::ConnectionAdapters::PostgreSQLColumn.include?(PostgreSQLColumn)
59
69
  end
@@ -130,7 +140,7 @@ module SchemaPlus
130
140
  result = query(<<-SQL, name)
131
141
 
132
142
  SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid), t.oid,
133
- m.amname, pg_get_expr(d.indpred, t.oid), pg_get_expr(d.indexprs, t.oid)
143
+ m.amname, pg_get_expr(d.indpred, t.oid) as conditions, pg_get_expr(d.indexprs, t.oid) as expression
134
144
  FROM pg_class t
135
145
  INNER JOIN pg_index d ON t.oid = d.indrelid
136
146
  INNER JOIN pg_class i ON d.indexrelid = i.oid
@@ -146,29 +156,38 @@ module SchemaPlus
146
156
  unique = (is_unique == 't')
147
157
  index_keys = indkey.split(" ")
148
158
 
149
- columns = Hash[query(<<-SQL, "Columns for index #{index_name} on #{table_name}")]
150
- SELECT a.attnum, a.attname
151
- FROM pg_attribute a
152
- WHERE a.attrelid = #{oid}
153
- AND a.attnum IN (#{index_keys.join(",")})
159
+ rows = query(<<-SQL, "Columns for index #{index_name} on #{table_name}")
160
+ SELECT CAST(a.attnum as VARCHAR), a.attname, t.typname
161
+ FROM pg_attribute a
162
+ INNER JOIN pg_type t ON a.atttypid = t.oid
163
+ WHERE a.attrelid = #{oid}
154
164
  SQL
165
+ columns = {}
166
+ types = {}
167
+ rows.each do |num, name, type|
168
+ columns[num] = name
169
+ types[name] = type
170
+ end
155
171
 
156
172
  column_names = columns.values_at(*index_keys).compact
157
173
  case_sensitive = true
158
174
 
159
175
  # extract column names from the expression, for a
160
- # case-insensitive index
176
+ # case-insensitive index.
177
+ # only applies to character, character varying, and text
161
178
  if expression
162
179
  rexp_lower = %r{\blower\(\(?([^)]+)(\)::text)?\)}
163
180
  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]
181
+ case_insensitive_columns = expression.scan(rexp_lower).map(&:first).select{|column| %W[char varchar text].include? types[column]}
182
+ if case_insensitive_columns.any?
183
+ case_sensitive = false
184
+ column_names = index_keys.map { |index_key|
185
+ index_key == '0' ? case_insensitive_columns.shift : columns[index_key]
186
+ }.compact
167
187
  end
168
- case_sensitive = false
169
188
  end
170
189
  end
171
-
190
+
172
191
  # add info on sort order for columns (only desc order is explicitly specified, asc is the default)
173
192
  desc_order_columns = inddef.scan(/(\w+) DESC/).flatten
174
193
  orders = desc_order_columns.any? ? Hash[column_names.map {|column| [column, desc_order_columns.include?(column) ? :desc : :asc]}] : {}
@@ -184,6 +203,10 @@ module SchemaPlus
184
203
  end
185
204
  end
186
205
 
206
+ def query(*args)
207
+ select(*args).map(&:values)
208
+ end if defined?(JRUBY_VERSION)
209
+
187
210
  def rename_table_with_schema_plus(oldname, newname) #:nodoc:
188
211
  rename_table_without_schema_plus(oldname, newname)
189
212
  rename_indexes_and_foreign_keys(oldname, newname)
@@ -289,14 +312,16 @@ module SchemaPlus
289
312
  foreign_keys
290
313
  end
291
314
 
292
- def default_expr_valid?(expr)
293
- true # arbitrary sql is okay in PostgreSQL
294
- end
315
+ module AddColumnOptions
316
+ def default_expr_valid?(expr)
317
+ true # arbitrary sql is okay in PostgreSQL
318
+ end
295
319
 
296
- def sql_for_function(function)
297
- case function
298
- when :now
299
- "NOW()"
320
+ def sql_for_function(function)
321
+ case function
322
+ when :now
323
+ "NOW()"
324
+ end
300
325
  end
301
326
  end
302
327
  end
@@ -76,6 +76,7 @@ module SchemaPlus::ActiveRecord::ConnectionAdapters
76
76
  # an error.)
77
77
  #
78
78
  def add_index_with_schema_plus(table, columns, options={})
79
+ options.delete(:if_exists)
79
80
  add_index_without_schema_plus(table, columns, options)
80
81
  rescue => e
81
82
  SchemaStatements.add_index_exception_handler(self, table, columns, options, e)
@@ -21,6 +21,7 @@ module SchemaPlus
21
21
  alias_method_chain :indexes, :schema_plus
22
22
  alias_method_chain :rename_table, :schema_plus
23
23
  end
24
+
24
25
  if ::ActiveRecord::VERSION::MAJOR.to_i < 4
25
26
  ::ActiveRecord::ConnectionAdapters::SQLiteColumn.send(:include, SQLiteColumn) unless ::ActiveRecord::ConnectionAdapters::SQLiteColumn.include?(SQLiteColumn)
26
27
  else
@@ -116,14 +117,16 @@ module SchemaPlus
116
117
  foreign_keys
117
118
  end
118
119
 
119
- def default_expr_valid?(expr)
120
- true # arbitrary sql is okay
121
- end
120
+ module AddColumnOptions
121
+ def default_expr_valid?(expr)
122
+ true # arbitrary sql is okay
123
+ end
122
124
 
123
- def sql_for_function(function)
124
- case function
125
- when :now
126
- "(DATETIME('now'))"
125
+ def sql_for_function(function)
126
+ case function
127
+ when :now
128
+ "(DATETIME('now'))"
129
+ end
127
130
  end
128
131
  end
129
132
  end
@@ -171,23 +171,14 @@ module SchemaPlus::ActiveRecord::ConnectionAdapters
171
171
  def remove_foreign_key(_, *args) #:nodoc:
172
172
  end
173
173
 
174
- # This is a deliberately empty stub. In fact, verifying that it won't
175
- # ever be called. The reason for it is that ColumnOptionsHandler will
176
- # remove a previous index when changing a column. But we don't do
177
- # column changes within table definitions.
178
- def remove_index(_, options) raise "InternalError: remove_index called in a table definition" ; end
179
-
180
- # Determines if an indexes is queued to be created. Called from
181
- # ColumnOptionsHandler as part of checking whether to auto-create an index
182
- def index_exists?(_, column_name, options={})
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
174
+ # This is a deliberately empty stub. The reason for it is that
175
+ # ColumnOptionsHandler will remove a previous index when changing a
176
+ # column. But we don't do column changes within table definitions.
177
+ # Presumably will be called with :if_exists true. If not, will raise
178
+ # an error.
179
+ def remove_index(_, options)
180
+ raise "InternalError: remove_index called in a table definition" unless options[:if_exists]
188
181
  end
189
182
 
190
-
191
-
192
183
  end
193
184
  end
@@ -0,0 +1,88 @@
1
+ module SchemaPlus
2
+ module ActiveRecord
3
+ module Migration
4
+ module CommandRecorder
5
+ include SchemaPlus::ActiveRecord::ColumnOptionsHandler
6
+
7
+ attr_accessor :schema_plus_config #:nodoc:
8
+
9
+ def self.included(base) #:nodoc:
10
+ base.class_eval do
11
+ alias_method_chain :add_column, :schema_plus
12
+ alias_method_chain :add_reference, :schema_plus unless ::ActiveRecord::VERSION::MAJOR.to_i < 4
13
+ alias_method_chain :invert_add_index, :schema_plus
14
+ end
15
+ end
16
+
17
+ def add_column_with_schema_plus(table_name, name, type, options = {}) #:nodoc:
18
+ add_column_without_schema_plus(table_name, name, type, options)
19
+ revertable_schema_plus_handle_column_options(table_name, name, options, :config => schema_plus_config)
20
+ self
21
+ end
22
+
23
+ # seems like this is fixing a rails bug:
24
+ # change_table foo, :bulk => true { |t| t.references :bar }
25
+ # results in an 'unknown method :add_reference_sql' (with mysql2)
26
+ #
27
+ # should track it down separately and submit a patch/fix to rails
28
+ #
29
+ def add_reference_with_schema_plus(table_name, ref_name, options = {}) #:nodoc:
30
+ # which is the worse hack...?
31
+ if RUBY_VERSION >= "2.0.0"
32
+ # .. rebinding a method from a different module? (can't do this in ruby 1.9.3)
33
+ ::ActiveRecord::ConnectionAdapters::SchemaStatements.instance_method(:add_reference).bind(self).call(table_name, ref_name, options)
34
+ else
35
+ # .. or copying and pasting the code?
36
+ polymorphic = options.delete(:polymorphic)
37
+ index_options = options.delete(:index)
38
+ add_column(table_name, "#{ref_name}_id", :integer, options)
39
+ add_column(table_name, "#{ref_name}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) if polymorphic
40
+ add_index(table_name, polymorphic ? %w[id type].map{ |t| "#{ref_name}_#{t}" } : "#{ref_name}_id", index_options.is_a?(Hash) ? index_options : nil) if index_options
41
+ end
42
+
43
+ self
44
+ end
45
+
46
+ if ::ActiveRecord::VERSION::MAJOR >= 4
47
+ def revertable_schema_plus_handle_column_options(table_name, name, options, config)
48
+ length = commands.length
49
+ schema_plus_handle_column_options(table_name, name, options, config)
50
+ if reverting
51
+ rev = []
52
+ while commands.length > length
53
+ cmd = commands.pop
54
+ rev.unshift cmd unless cmd[0].to_s =~ /^add_/
55
+ end
56
+ commands.concat rev
57
+ end
58
+ end
59
+ else
60
+ alias :revertable_schema_plus_handle_column_options :schema_plus_handle_column_options
61
+ end
62
+
63
+ def add_foreign_key(*args)
64
+ record(:add_foreign_key, args)
65
+ end
66
+
67
+ def invert_add_foreign_key(args)
68
+ table_name, column_names, references_table_name, references_column_names, options = args
69
+ [:remove_foreign_key, [table_name, column_names, references_table_name, references_column_names, (options||{}).merge(if_exists: true)]]
70
+ end
71
+
72
+ def invert_add_index_with_schema_plus(args)
73
+ table, columns, options = *args
74
+ [:remove_index, [table, (options||{}).merge(column: columns, if_exists: true)]]
75
+ end
76
+
77
+ def remove_foreign_key(*args)
78
+ record(:remove_foreign_key, args)
79
+ end
80
+
81
+ def invert_remove_foreign_key(args)
82
+ [:add_foreign_key, args]
83
+ end
84
+
85
+ end
86
+ end
87
+ end
88
+ end
@@ -126,7 +126,7 @@ module SchemaPlus
126
126
  dump << ", :conditions => #{index.conditions.inspect}" unless index.conditions.blank?
127
127
  index_lengths = index.lengths.compact if index.lengths.is_a?(Array)
128
128
  dump << ", :length => #{Hash[*index.columns.zip(index.lengths).flatten].inspect}" if index_lengths.present?
129
- dump << ", :order => {" + index.columns.map{|column| column.inspect + " => " + (index.orders[column] || :asc).inspect}.join(", ") + "}" if index.orders
129
+ dump << ", :order => {" + index.orders.map{|column, val| "#{column.inspect} => #{val.inspect}"}.join(", ") + "}" unless index.orders.blank?
130
130
  else
131
131
  dump << " :name => #{index.name.inspect}"
132
132
  dump << ", :kind => \"#{index.kind}\"" unless index.kind.blank?
@@ -1,3 +1,3 @@
1
1
  module SchemaPlus
2
- VERSION = "1.2.0"
2
+ VERSION = "1.3.0"
3
3
  end
data/lib/schema_plus.rb CHANGED
@@ -13,6 +13,7 @@ require 'schema_plus/active_record/connection_adapters/abstract_adapter'
13
13
  require 'schema_plus/active_record/connection_adapters/column'
14
14
  require 'schema_plus/active_record/connection_adapters/foreign_key_definition'
15
15
  require 'schema_plus/active_record/connection_adapters/index_definition'
16
+ require 'schema_plus/active_record/migration/command_recorder'
16
17
  require 'schema_plus/railtie' if defined?(Rails::Railtie)
17
18
 
18
19
  module SchemaPlus
@@ -124,10 +125,18 @@ module SchemaPlus
124
125
  ::ActiveRecord::ConnectionAdapters::IndexDefinition.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::IndexDefinition)
125
126
  ::ActiveRecord::ConnectionAdapters::SchemaStatements.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::SchemaStatements)
126
127
  ::ActiveRecord::ConnectionAdapters::TableDefinition.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::TableDefinition)
128
+ ::ActiveRecord::Migration::CommandRecorder.send(:include, SchemaPlus::ActiveRecord::Migration::CommandRecorder)
129
+
130
+ if "#{::ActiveRecord::VERSION::MAJOR}.#{::ActiveRecord::VERSION::MINOR}".to_r >= "4.1".to_r
131
+ ::ActiveRecord::ConnectionAdapters::AbstractAdapter::SchemaCreation.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::AbstractAdapter::AddColumnOptions)
132
+ else
133
+ ::ActiveRecord::ConnectionAdapters::AbstractAdapter.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::AbstractAdapter::AddColumnOptions)
134
+ end
127
135
 
128
136
  if ::ActiveRecord::VERSION::MAJOR.to_i >= 4
129
- ::ActiveRecord::ConnectionAdapters::AbstractAdapter::SchemaCreation.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::AbstractAdapter::SchemaCreation)
137
+ ::ActiveRecord::ConnectionAdapters::AbstractAdapter::SchemaCreation.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::AbstractAdapter::VisitTableDefinition)
130
138
  end
139
+
131
140
  end
132
141
 
133
142
  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.3 2.0.0]
9
- RAILS_VERSIONS = %W[3.2 4.0]
8
+ RUBY_VERSIONS = %W[jruby 1.9.3 2.0.0]
9
+ RAILS_VERSIONS = %W[3.2 edge 4.0]
10
10
  DB_ADAPTERS = %W[postgresql mysql mysql2 sqlite3]
11
11
 
12
12
  o = OpenStruct.new
@@ -66,14 +66,33 @@ combos = o.ruby_versions.product(o.rails_versions, o.db_adapters).map{|product|
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
68
  when combo.rails >= "4" && combo.db_adapter == "mysql" then false
69
+ when combo.ruby == "jruby"
70
+ case
71
+ when combo.rails == "3.2" && combo.db_adapter == "postgresql" then true
72
+ else false
73
+ end
69
74
  else true
70
75
  end
71
76
  }
72
77
 
73
- def ruby_version_selector(ruby)
74
- if @use_rvm ||= system("which -s rvm")
78
+ if system("which -s rvm")
79
+ # using rvm
80
+ def ruby_version_selector(ruby)
75
81
  "rvm #{ruby} do"
76
- else
82
+ end
83
+ else
84
+ # using rbenv.
85
+ #
86
+ # because we're running within a ruby program that was launched by
87
+ # rbenv, we already have various environment variables set up. need
88
+ # strip those out so that the forked shell can run a diifferent ruby
89
+ # version than the one we're in now.
90
+ ENV['PATH'] = ENV['PATH'].split(':').reject{|dir| dir =~ %r{/rbenv/(?!shims)}}.join(':')
91
+ ENV['GEM_PATH'] = ENV['GEM_PATH'].split(':').reject{|dir| dir =~ %r{/rbenv}}.join(':')
92
+ ENV['RBENV_DIR'] = nil
93
+ ENV['RBENV_HOOK_PATH'] = nil
94
+
95
+ def ruby_version_selector(ruby)
77
96
  @versions ||= `rbenv versions --bare`.split
78
97
  version = @versions.select{|v| v.start_with? ruby}.last || abort("no ruby version '#{ruby}' installed in rbenv")
79
98
  "RBENV_VERSION=#{version}"
@@ -23,7 +23,13 @@ describe "Column definition" do
23
23
  end
24
24
  end
25
25
 
26
- let(:connection) { ActiveRecord::Base.connection }
26
+ def call_add_column_options!(*params, &block)
27
+ if ::ActiveRecord::VERSION::MAJOR >= 4
28
+ ActiveRecord::Base.connection.schema_creation.send(:add_column_options!, *params, &block)
29
+ else
30
+ ActiveRecord::Base.connection.add_column_options!(*params, &block)
31
+ end
32
+ end
27
33
 
28
34
  context "text columns" do
29
35
  before(:each) do
@@ -32,7 +38,7 @@ describe "Column definition" do
32
38
 
33
39
  context "just default passed" do
34
40
  before(:each) do
35
- connection.add_column_options!(@sql, { :default => "2011-12-11 00:00:00" })
41
+ call_add_column_options!(@sql, { :default => "2011-12-11 00:00:00" })
36
42
  end
37
43
 
38
44
  subject { @sql}
@@ -44,7 +50,7 @@ describe "Column definition" do
44
50
 
45
51
  context "just default passed in hash" do
46
52
  before(:each) do
47
- connection.add_column_options!(@sql, { :default => { :value => "2011-12-11 00:00:00" } })
53
+ call_add_column_options!(@sql, { :default => { :value => "2011-12-11 00:00:00" } })
48
54
  end
49
55
 
50
56
  subject { @sql}
@@ -54,10 +60,34 @@ describe "Column definition" do
54
60
  end
55
61
  end
56
62
 
63
+ context "default passed with no nulls" do
64
+ before(:each) do
65
+ call_add_column_options!(@sql, { :default => "2011-12-11 00:00:00", null: false })
66
+ end
67
+
68
+ subject { @sql}
69
+
70
+ it "should use the normal default" do
71
+ should == "time_taken text DEFAULT '2011-12-11 00:00:00' NOT NULL"
72
+ end
73
+ end
74
+
75
+ context "default passed in hash with no nulls" do
76
+ before(:each) do
77
+ call_add_column_options!(@sql, { :default => { :value => "2011-12-11 00:00:00" }, null: false })
78
+ end
79
+
80
+ subject { @sql}
81
+
82
+ it "should use the normal default" do
83
+ should == "time_taken text DEFAULT '2011-12-11 00:00:00' NOT NULL"
84
+ end
85
+ end
86
+
57
87
  context "default function passed as now" do
58
88
  before(:each) do
59
89
  begin
60
- connection.add_column_options!(@sql, { :default => :now })
90
+ call_add_column_options!(@sql, { :default => :now })
61
91
  rescue ArgumentError => e
62
92
  @raised_argument_error = e
63
93
  end
@@ -84,8 +114,38 @@ describe "Column definition" do
84
114
  end
85
115
  end
86
116
 
117
+ context "default function passed as now with no nulls" do
118
+ before(:each) do
119
+ begin
120
+ call_add_column_options!(@sql, { :default => :now, null: false })
121
+ rescue ArgumentError => e
122
+ @raised_argument_error = e
123
+ end
124
+ end
125
+
126
+ subject { @sql }
127
+
128
+ if SchemaPlusHelpers.postgresql?
129
+ it "should use NOW() as the default" do
130
+ should == "time_taken text DEFAULT NOW() NOT NULL"
131
+ end
132
+ end
133
+
134
+ if SchemaPlusHelpers.sqlite3?
135
+ it "should use NOW() as the default" do
136
+ should == "time_taken text DEFAULT (DATETIME('now')) NOT NULL"
137
+ end
138
+ end
139
+
140
+ if SchemaPlusHelpers.mysql?
141
+ it "should raise an error" do
142
+ @raised_argument_error.should be_a ArgumentError
143
+ end
144
+ end
145
+ end
146
+
87
147
  context "valid expr passed as default" do
88
- subject { connection.add_column_options!(@sql, { :default => { :expr => 'NOW()' } }); @sql }
148
+ subject { call_add_column_options!(@sql, { :default => { :expr => 'NOW()' } }); @sql }
89
149
 
90
150
  if SchemaPlusHelpers.postgresql?
91
151
  it "should use NOW() as the default" do
@@ -109,11 +169,11 @@ describe "Column definition" do
109
169
  context "invalid expr passed as default" do
110
170
  if SchemaPlusHelpers.mysql?
111
171
  it "should raise an error" do
112
- lambda {connection.add_column_options!(@sql, { :default => { :expr => "ARBITRARY_EXPR" } })}.should raise_error ArgumentError
172
+ lambda {call_add_column_options!(@sql, { :default => { :expr => "ARBITRARY_EXPR" } })}.should raise_error ArgumentError
113
173
  end
114
174
  else
115
175
  it "should just accept the SQL" do
116
- connection.add_column_options!(@sql, { :default => { :expr => "ARBITRARY_EXPR" } })
176
+ call_add_column_options!(@sql, { :default => { :expr => "ARBITRARY_EXPR" } })
117
177
  @sql.should == "time_taken text DEFAULT ARBITRARY_EXPR"
118
178
  end
119
179
  end
@@ -127,7 +187,7 @@ describe "Column definition" do
127
187
 
128
188
  context "passed as boolean false" do
129
189
  before(:each) do
130
- connection.add_column_options!(@sql, { :default => false })
190
+ call_add_column_options!(@sql, { :default => false })
131
191
  end
132
192
 
133
193
  subject { @sql}
@@ -139,7 +199,7 @@ describe "Column definition" do
139
199
 
140
200
  context "passed as boolean true" do
141
201
  before(:each) do
142
- connection.add_column_options!(@sql, { :default => true })
202
+ call_add_column_options!(@sql, { :default => true })
143
203
  end
144
204
 
145
205
  subject { @sql}
@@ -180,6 +180,31 @@ describe "Index definition" do
180
180
 
181
181
  end
182
182
 
183
+ context "when index has a non-btree type" do
184
+ before(:each) do
185
+ migration.execute "CREATE INDEX users_login_index ON users USING hash(login)"
186
+ User.reset_column_information
187
+ @index = User.indexes.detect { |i| i.name == "users_login_index" }
188
+ end
189
+
190
+ it "exists" do
191
+ @index.should_not be_nil
192
+ end
193
+
194
+ it "defines kind" do
195
+ @index.kind.should == "hash"
196
+ end
197
+
198
+ it "does not define expression" do
199
+ @index.expression.should be_nil
200
+ end
201
+
202
+ it "does not define order" do
203
+ @index.orders.should be_blank
204
+ end
205
+ end
206
+
207
+
183
208
  end # of postgresql specific examples
184
209
 
185
210
  protected
data/spec/index_spec.rb CHANGED
@@ -103,7 +103,7 @@ describe "add_index" do
103
103
 
104
104
  it "should allow to specify actual expression only" do
105
105
  add_index(:users, :expression => "upper(login)", :name => 'users_login_index')
106
- @index = User.indexes.detect { |i| i.expression.present? }
106
+ @index = User.indexes.detect { |i| i.name == 'users_login_index' }
107
107
  @index.expression.should == "upper((login)::text)"
108
108
  end
109
109