schema_plus 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.travis.yml +29 -0
  4. data/README.md +19 -0
  5. data/gemfiles/rails-3.2/Gemfile.mysql +7 -1
  6. data/gemfiles/rails-3.2/Gemfile.mysql2 +7 -1
  7. data/gemfiles/rails-3.2/Gemfile.postgresql +7 -1
  8. data/gemfiles/rails-3.2/Gemfile.sqlite3 +7 -1
  9. data/gemfiles/rails-4.0/Gemfile.mysql2 +7 -1
  10. data/gemfiles/rails-4.0/Gemfile.postgresql +7 -1
  11. data/gemfiles/rails-4.0/Gemfile.sqlite3 +7 -1
  12. data/gemfiles/rails-edge/Gemfile.mysql2 +7 -1
  13. data/gemfiles/rails-edge/Gemfile.postgresql +7 -1
  14. data/gemfiles/rails-edge/Gemfile.sqlite3 +7 -1
  15. data/lib/schema_plus/active_record/column_options_handler.rb +2 -2
  16. data/lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb +124 -57
  17. data/lib/schema_plus/active_record/connection_adapters/foreign_key_definition.rb +9 -2
  18. data/lib/schema_plus/active_record/connection_adapters/mysql_adapter.rb +30 -10
  19. data/lib/schema_plus/active_record/connection_adapters/postgresql_adapter.rb +55 -30
  20. data/lib/schema_plus/active_record/connection_adapters/schema_statements.rb +1 -0
  21. data/lib/schema_plus/active_record/connection_adapters/sqlite3_adapter.rb +10 -7
  22. data/lib/schema_plus/active_record/connection_adapters/table_definition.rb +7 -16
  23. data/lib/schema_plus/active_record/migration/command_recorder.rb +88 -0
  24. data/lib/schema_plus/active_record/schema_dumper.rb +1 -1
  25. data/lib/schema_plus/version.rb +1 -1
  26. data/lib/schema_plus.rb +10 -1
  27. data/runspecs +24 -5
  28. data/spec/column_definition_spec.rb +69 -9
  29. data/spec/index_definition_spec.rb +25 -0
  30. data/spec/index_spec.rb +1 -1
  31. data/spec/migration_spec.rb +76 -11
  32. data/spec/schema_dumper_spec.rb +19 -5
  33. metadata +3 -2
@@ -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