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.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.travis.yml +29 -0
- data/README.md +19 -0
- data/gemfiles/rails-3.2/Gemfile.mysql +7 -1
- data/gemfiles/rails-3.2/Gemfile.mysql2 +7 -1
- data/gemfiles/rails-3.2/Gemfile.postgresql +7 -1
- data/gemfiles/rails-3.2/Gemfile.sqlite3 +7 -1
- data/gemfiles/rails-4.0/Gemfile.mysql2 +7 -1
- data/gemfiles/rails-4.0/Gemfile.postgresql +7 -1
- data/gemfiles/rails-4.0/Gemfile.sqlite3 +7 -1
- data/gemfiles/rails-edge/Gemfile.mysql2 +7 -1
- data/gemfiles/rails-edge/Gemfile.postgresql +7 -1
- data/gemfiles/rails-edge/Gemfile.sqlite3 +7 -1
- data/lib/schema_plus/active_record/column_options_handler.rb +2 -2
- data/lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb +124 -57
- data/lib/schema_plus/active_record/connection_adapters/foreign_key_definition.rb +9 -2
- data/lib/schema_plus/active_record/connection_adapters/mysql_adapter.rb +30 -10
- data/lib/schema_plus/active_record/connection_adapters/postgresql_adapter.rb +55 -30
- data/lib/schema_plus/active_record/connection_adapters/schema_statements.rb +1 -0
- data/lib/schema_plus/active_record/connection_adapters/sqlite3_adapter.rb +10 -7
- data/lib/schema_plus/active_record/connection_adapters/table_definition.rb +7 -16
- data/lib/schema_plus/active_record/migration/command_recorder.rb +88 -0
- data/lib/schema_plus/active_record/schema_dumper.rb +1 -1
- data/lib/schema_plus/version.rb +1 -1
- data/lib/schema_plus.rb +10 -1
- data/runspecs +24 -5
- data/spec/column_definition_spec.rb +69 -9
- data/spec/index_definition_spec.rb +25 -0
- data/spec/index_spec.rb +1 -1
- data/spec/migration_spec.rb +76 -11
- data/spec/schema_dumper_spec.rb +19 -5
- 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
|
-
|
10
|
-
|
11
|
-
|
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
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
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
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
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
|
-
|
166
|
-
|
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
|
-
|
293
|
-
|
294
|
-
|
315
|
+
module AddColumnOptions
|
316
|
+
def default_expr_valid?(expr)
|
317
|
+
true # arbitrary sql is okay in PostgreSQL
|
318
|
+
end
|
295
319
|
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
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
|
-
|
120
|
-
|
121
|
-
|
120
|
+
module AddColumnOptions
|
121
|
+
def default_expr_valid?(expr)
|
122
|
+
true # arbitrary sql is okay
|
123
|
+
end
|
122
124
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
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.
|
175
|
-
#
|
176
|
-
#
|
177
|
-
#
|
178
|
-
|
179
|
-
|
180
|
-
|
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.
|
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?
|
data/lib/schema_plus/version.rb
CHANGED
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::
|
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
|
-
|
74
|
-
|
78
|
+
if system("which -s rvm")
|
79
|
+
# using rvm
|
80
|
+
def ruby_version_selector(ruby)
|
75
81
|
"rvm #{ruby} do"
|
76
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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 {
|
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 {
|
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
|
-
|
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
|
-
|
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
|
-
|
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.
|
106
|
+
@index = User.indexes.detect { |i| i.name == 'users_login_index' }
|
107
107
|
@index.expression.should == "upper((login)::text)"
|
108
108
|
end
|
109
109
|
|