schema_plus 1.8.9 → 2.0.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -4
  3. data/.travis.yml +1 -47
  4. data/CHANGELOG.md +0 -35
  5. data/README.md +73 -107
  6. data/Rakefile +7 -10
  7. data/TODO.md +51 -0
  8. data/gemfiles/Gemfile.base +2 -0
  9. data/lib/schema_column_plus.rb +7 -0
  10. data/lib/{schema_plus → schema_column_plus}/active_record/connection_adapters/column.rb +13 -11
  11. data/lib/schema_column_plus/middleware/model.rb +22 -0
  12. data/lib/schema_db_default.rb +13 -0
  13. data/lib/{schema_plus → schema_db_default}/active_record/attribute.rb +4 -4
  14. data/lib/schema_db_default/db_default.rb +17 -0
  15. data/lib/schema_db_default/middleware.rb +30 -0
  16. data/lib/schema_default_expr.rb +32 -0
  17. data/lib/schema_default_expr/active_record/connection_adapters/mysql_adapter.rb +17 -0
  18. data/lib/schema_default_expr/active_record/connection_adapters/postgresql_adapter.rb +18 -0
  19. data/lib/schema_default_expr/active_record/connection_adapters/sqlite3_adapter.rb +35 -0
  20. data/lib/schema_default_expr/middleware.rb +54 -0
  21. data/lib/schema_pg_enums.rb +6 -0
  22. data/lib/schema_pg_enums/active_record.rb +69 -0
  23. data/lib/schema_pg_enums/middleware.rb +23 -0
  24. data/lib/schema_plus.rb +17 -45
  25. data/lib/schema_plus/active_record/base.rb +6 -23
  26. data/lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb +80 -181
  27. data/lib/schema_plus/active_record/connection_adapters/foreign_key_definition.rb +78 -99
  28. data/lib/schema_plus/active_record/connection_adapters/mysql_adapter.rb +34 -114
  29. data/lib/schema_plus/active_record/connection_adapters/postgresql_adapter.rb +16 -370
  30. data/lib/schema_plus/active_record/connection_adapters/schema_statements.rb +1 -67
  31. data/lib/schema_plus/active_record/connection_adapters/sqlite3_adapter.rb +18 -112
  32. data/lib/schema_plus/active_record/connection_adapters/table_definition.rb +14 -116
  33. data/lib/schema_plus/active_record/migration/command_recorder.rb +8 -59
  34. data/lib/schema_plus/middleware/dumper.rb +94 -0
  35. data/lib/schema_plus/middleware/migration.rb +167 -0
  36. data/lib/schema_plus/middleware/model.rb +17 -0
  37. data/lib/schema_plus/version.rb +1 -1
  38. data/lib/schema_plus_tables.rb +15 -0
  39. data/lib/schema_plus_tables/active_record/connection_adapters/abstract_adapter.rb +20 -0
  40. data/lib/schema_plus_tables/active_record/connection_adapters/mysql_adapter.rb +25 -0
  41. data/lib/schema_plus_tables/active_record/connection_adapters/postgresql_adapter.rb +13 -0
  42. data/lib/schema_plus_tables/active_record/connection_adapters/sqlite3_adapter.rb +12 -0
  43. data/lib/schema_views.rb +16 -0
  44. data/lib/schema_views/active_record/connection_adapters/abstract_adapter.rb +41 -0
  45. data/lib/schema_views/active_record/connection_adapters/mysql_adapter.rb +30 -0
  46. data/lib/schema_views/active_record/connection_adapters/postgresql_adapter.rb +31 -0
  47. data/lib/schema_views/active_record/connection_adapters/sqlite3_adapter.rb +18 -0
  48. data/lib/schema_views/middleware.rb +47 -0
  49. data/schema_dev.yml +1 -31
  50. data/schema_plus.gemspec +11 -9
  51. data/spec/foreign_key_definition_spec.rb +7 -7
  52. data/spec/foreign_key_spec.rb +63 -48
  53. data/spec/migration_spec.rb +58 -203
  54. data/spec/named_schemas_spec.rb +5 -88
  55. data/spec/{column_spec.rb → schema_column_plus/column_spec.rb} +26 -48
  56. data/spec/schema_db_default/column_spec.rb +58 -0
  57. data/spec/{column_default_spec.rb → schema_default_expr/column_default_spec.rb} +1 -2
  58. data/spec/schema_default_expr/schema_dumper_spec.rb +116 -0
  59. data/spec/schema_dumper_spec.rb +22 -327
  60. data/spec/{enum_spec.rb → schema_pg_enums/enum_spec.rb} +1 -1
  61. data/spec/schema_pg_enums/schema_dumper_spec.rb +37 -0
  62. data/spec/schema_views/named_schemas_spec.rb +97 -0
  63. data/spec/{views_spec.rb → schema_views/views_spec.rb} +1 -1
  64. data/spec/spec_helper.rb +2 -1
  65. data/spec/support/matchers/reference.rb +11 -12
  66. metadata +104 -57
  67. data/gemfiles/rails-3.2/Gemfile.base +0 -3
  68. data/gemfiles/rails-3.2/Gemfile.mysql +0 -10
  69. data/gemfiles/rails-3.2/Gemfile.mysql2 +0 -10
  70. data/gemfiles/rails-3.2/Gemfile.postgresql +0 -10
  71. data/gemfiles/rails-3.2/Gemfile.sqlite3 +0 -10
  72. data/gemfiles/rails-4.0/Gemfile.base +0 -3
  73. data/gemfiles/rails-4.0/Gemfile.mysql2 +0 -10
  74. data/gemfiles/rails-4.0/Gemfile.postgresql +0 -10
  75. data/gemfiles/rails-4.0/Gemfile.sqlite3 +0 -10
  76. data/gemfiles/rails-4.1/Gemfile.base +0 -3
  77. data/gemfiles/rails-4.1/Gemfile.mysql2 +0 -10
  78. data/gemfiles/rails-4.1/Gemfile.postgresql +0 -10
  79. data/gemfiles/rails-4.1/Gemfile.sqlite3 +0 -10
  80. data/lib/schema_plus/active_record/column_options_handler.rb +0 -117
  81. data/lib/schema_plus/active_record/connection_adapters/index_definition.rb +0 -70
  82. data/lib/schema_plus/active_record/db_default.rb +0 -19
  83. data/lib/schema_plus/active_record/foreign_keys.rb +0 -137
  84. data/lib/schema_plus/active_record/schema_dumper.rb +0 -171
  85. data/lib/schema_plus/railtie.rb +0 -20
  86. data/spec/index_definition_spec.rb +0 -211
  87. data/spec/index_spec.rb +0 -249
@@ -1,171 +0,0 @@
1
- require 'tsort'
2
-
3
- module SchemaPlus
4
- module ActiveRecord
5
-
6
- # SchemaPlus modifies ActiveRecord's schema dumper to include foreign
7
- # key constraints and views.
8
- #
9
- # Additionally, index and foreign key constraint definitions are dumped
10
- # inline in the create_table block. (This is done for elegance, but
11
- # also because Sqlite3 does not allow foreign key constraints to be
12
- # added to a table after it has been defined.)
13
- #
14
- # The tables and views are dumped in alphabetical order, subject to
15
- # topological sort constraints that a table must be dumped before any
16
- # view that references it or table that has a foreign key constaint to
17
- # it.
18
- #
19
- module SchemaDumper
20
-
21
- include TSort
22
-
23
- def self.included(base) #:nodoc:
24
- base.class_eval do
25
- private
26
- alias_method_chain :table, :schema_plus
27
- alias_method_chain :tables, :schema_plus
28
- alias_method_chain :indexes, :schema_plus
29
- alias_method_chain :foreign_keys, :schema_plus if private_method_defined? :foreign_keys
30
- end
31
- end
32
-
33
- private
34
-
35
- def foreign_keys_with_schema_plus(*)
36
- # do nothing. this overrides AR 4.2's foreign key dumping method, which isn't needed
37
- # because we're dong them inline
38
- end
39
-
40
- def break_fk_cycles #:nodoc:
41
- strongly_connected_components.select{|component| component.size > 1}.each do |tables|
42
- table = tables.sort.last
43
- backref_fks = @inline_fks[table].select{|fk| tables.include?(fk.references_table_name)}
44
- @inline_fks[table] -= backref_fks
45
- @dump_dependencies[table] -= backref_fks.collect(&:references_table_name)
46
- backref_fks.each do |fk|
47
- @backref_fks[fk.references_table_name] << fk
48
- end
49
- end
50
- end
51
-
52
- def tables_with_schema_plus(stream) #:nodoc:
53
- @table_dumps = {}
54
- @inline_fks = Hash.new{ |h, k| h[k] = [] }
55
- @backref_fks = Hash.new{ |h, k| h[k] = [] }
56
- @dump_dependencies = {}
57
-
58
- if @connection.respond_to?(:enums)
59
- @connection.enums.each do |schema, name, values|
60
- params = [name.inspect]
61
- params << values.map(&:inspect).join(', ')
62
- params << ":schema => #{schema.inspect}" if schema != 'public'
63
-
64
- stream.puts " create_enum #{params.join(', ')}"
65
- end
66
- end
67
-
68
- if "#{::ActiveRecord::VERSION::MAJOR}.#{::ActiveRecord::VERSION::MINOR}".to_r < "4.2".to_r
69
- tables_without_schema_plus(nil)
70
- else
71
- tables_without_schema_plus(stream)
72
- end
73
-
74
- @connection.views.each do |view_name|
75
- next if Array.wrap(::ActiveRecord::SchemaDumper.ignore_tables).any? {|pattern| view_name.match pattern}
76
- definition = @connection.view_definition(view_name)
77
- @table_dumps[view_name] = " create_view #{view_name.inspect}, #{definition.inspect}, :force => true\n"
78
- end
79
-
80
- re_view_referent = %r{(?:(?i)FROM|JOIN) \S*\b(#{(@table_dumps.keys).join('|')})\b}
81
- @table_dumps.keys.each do |table|
82
- if @connection.views.include?(table)
83
- dependencies = @connection.view_definition(table).scan(re_view_referent).flatten
84
- else
85
- @inline_fks[table] = @connection.foreign_keys(table)
86
- dependencies = @inline_fks[table].collect(&:references_table_name)
87
- end
88
- # select against @table_dumps keys to respect filtering based on
89
- # SchemaDumper.ignore_tables (which was taken into account
90
- # increate @table_dumps)
91
- @dump_dependencies[table] = dependencies.sort.uniq.select {|name| @table_dumps.has_key? name}
92
- end
93
-
94
- # Normally we dump foreign key constraints inline in the table
95
- # definitions, both for visual cleanliness and because sqlite3
96
- # doesn't allow foreign key constraints to be added afterwards.
97
- # But in case there's a cycle in the constraint references, some
98
- # constraints will need to be broken out then added later. (Adding
99
- # constraints later won't work with sqlite3, but that means sqlite3
100
- # won't let you create cycles in the first place.)
101
- break_fk_cycles while strongly_connected_components.any?{|component| component.size > 1}
102
-
103
- tsort().each do |table|
104
- table_dump = @table_dumps[table]
105
- if i = (table_dump =~ /^\s*[e]nd\s*$/)
106
- table_dump.insert i, dump_indexes(table) + dump_foreign_keys(@inline_fks[table], :inline => true)
107
- end
108
- stream.print table_dump
109
- stream.puts dump_foreign_keys(@backref_fks[table], :inline => false)+"\n" if @backref_fks[table].any?
110
- end
111
-
112
- end
113
-
114
- def tsort_each_node(&block) #:nodoc:
115
- @table_dumps.keys.sort.each(&block)
116
- end
117
-
118
- def tsort_each_child(table, &block) #:nodoc:
119
- @dump_dependencies[table].each(&block)
120
- end
121
-
122
- def table_with_schema_plus(table, ignore) #:nodoc:
123
- stream = StringIO.new
124
- table_without_schema_plus(table, stream)
125
- stream_string = stream.string
126
- @connection.columns(table).each do |column|
127
- if "#{::ActiveRecord::VERSION::MAJOR}.#{::ActiveRecord::VERSION::MINOR}".to_r < "4.2".to_r
128
- if !column.default_expr.nil?
129
- stream_string.gsub!("\"#{column.name}\"", "\"#{column.name}\", :default => { :expr => #{column.default_expr.inspect} }")
130
- end
131
- else
132
- if !column.default_function.nil?
133
- stream_string.gsub!("\"#{column.name}\"", "\"#{column.name}\", :default => { :expr => #{column.default_function.inspect} }")
134
- end
135
- end
136
- end
137
- @table_dumps[table] = stream_string
138
- end
139
-
140
- def indexes_with_schema_plus(table, stream) #:nodoc:
141
- # do nothing. we've already taken care of indexes as part of
142
- # dumping the tables
143
- end
144
-
145
- def dump_indexes(table) #:nodoc:
146
- @connection.indexes(table).collect{ |index|
147
- dump = " t.index"
148
- dump << " #{index.columns.inspect}," unless index.columns.blank?
149
- dump << " :name => #{index.name.inspect}"
150
- dump << ", :unique => true" if index.unique
151
- dump << ", :kind => \"#{index.kind}\"" unless index.kind.blank?
152
- unless index.columns.blank?
153
- dump << ", :case_sensitive => false" unless index.case_sensitive?
154
- dump << ", :conditions => #{index.conditions.inspect}" unless index.conditions.blank?
155
- index_lengths = index.lengths.compact if index.lengths.is_a?(Array)
156
- dump << ", :length => #{Hash[*index.columns.zip(index.lengths).flatten].inspect}" if index_lengths.present?
157
- dump << ", :order => {" + index.orders.map{|column, val| "#{column.inspect} => #{val.inspect}"}.join(", ") + "}" unless index.orders.blank?
158
- dump << ", :operator_class => {" + index.operator_classes.map{|column, val| "#{column.inspect} => #{val.inspect}"}.join(", ") + "}" unless index.operator_classes.blank?
159
- else
160
- dump << ", :expression => #{index.expression.inspect}"
161
- end
162
- dump << "\n"
163
- }.sort.join
164
- end
165
-
166
- def dump_foreign_keys(foreign_keys, opts={}) #:nodoc:
167
- foreign_keys.collect{ |foreign_key| " " + foreign_key.to_dump(:inline => opts[:inline]) }.sort.join
168
- end
169
- end
170
- end
171
- end
@@ -1,20 +0,0 @@
1
- module SchemaPlus
2
- class Railtie < Rails::Railtie #:nodoc:
3
-
4
- initializer 'schema_plus.insert', :before => "active_record.initialize_database" do
5
- ActiveSupport.on_load(:active_record) do
6
- SchemaPlus.insert
7
- end
8
- end
9
-
10
- rake_tasks do
11
- load 'rails/tasks/database.rake'
12
- ['db:schema:dump', 'db:schema:load'].each do |name|
13
- if task = Rake.application.tasks.find { |task| task.name == name }
14
- task.enhance(["schema_plus:load"])
15
- end
16
- end
17
- end
18
-
19
- end
20
- end
@@ -1,211 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
-
3
-
4
- describe "Index definition" do
5
-
6
- let(:migration) { ::ActiveRecord::Migration }
7
-
8
- before(:all) do
9
- define_schema(:auto_create => false) do
10
- create_table :users, :force => true do |t|
11
- t.string :login
12
- t.datetime :deleted_at
13
- end
14
-
15
- create_table :posts, :force => true do |t|
16
- t.text :body
17
- t.integer :user_id
18
- t.integer :author_id
19
- end
20
-
21
- create_table :comments, :force => true do |t|
22
- t.text :body
23
- t.integer :post_id
24
- t.foreign_key :post_id, :posts, :id
25
- end
26
- end
27
- class User < ::ActiveRecord::Base ; end
28
- class Post < ::ActiveRecord::Base ; end
29
- class Comment < ::ActiveRecord::Base ; end
30
- end
31
-
32
- around(:each) do |example|
33
- migration.suppress_messages do
34
- example.run
35
- end
36
- end
37
-
38
- after(:each) do
39
- migration.remove_index :users, :name => 'users_login_index' if migration.index_name_exists? :users, 'users_login_index', true
40
- end
41
-
42
- context "when index is multicolumn" do
43
- before(:each) do
44
- migration.execute "CREATE INDEX users_login_index ON users (login, deleted_at)"
45
- User.reset_column_information
46
- @index = index_definition(%w[login deleted_at])
47
- end
48
-
49
- it "is included in User.indexes" do
50
- expect(@index).not_to be_nil
51
- end
52
-
53
- end
54
-
55
- it "should correctly report supports_partial_indexes?" do
56
- query = lambda { migration.execute "CREATE INDEX users_login_index ON users(login) WHERE deleted_at IS NULL" }
57
- if migration.supports_partial_indexes?
58
- expect(query).not_to raise_error
59
- else
60
- expect(query).to raise_error
61
- end
62
- end
63
-
64
- it "should not crash on equality test with nil" do
65
- index = ActiveRecord::ConnectionAdapters::IndexDefinition.new(:table, :column)
66
- expect{index == nil}.to_not raise_error
67
- expect(index == nil).to be false
68
- end
69
-
70
-
71
- context "when index is ordered", :mysql => :skip do
72
-
73
- quotes = [
74
- ["unquoted", ''],
75
- ["double-quoted", '"'],
76
- ]
77
- quotes += [
78
- ["single-quoted", "'"],
79
- ["back-quoted", '`']
80
- ] if SchemaDev::Rspec::Helpers.sqlite3?
81
-
82
- quotes.each do |quotename, quote|
83
- it "index definition includes orders for #{quotename} columns" do
84
- migration.execute "CREATE INDEX users_login_index ON users (#{quote}login#{quote} DESC, #{quote}deleted_at#{quote} ASC)"
85
- User.reset_column_information
86
- index = index_definition(%w[login deleted_at])
87
- expect(index.orders).to eq({"login" => :desc, "deleted_at" => :asc})
88
- end
89
-
90
- end
91
- end
92
-
93
-
94
- context "when case insensitive is added", :postgresql => :only do
95
-
96
- before(:each) do
97
- migration.execute "CREATE INDEX users_login_index ON users(LOWER(login))"
98
- User.reset_column_information
99
- @index = User.indexes.detect { |i| i.expression =~ /lower\(\(login\)::text\)/i }
100
- end
101
-
102
- it "is included in User.indexes" do
103
- expect(@index).not_to be_nil
104
- end
105
-
106
- it "is not case_sensitive" do
107
- expect(@index).not_to be_case_sensitive
108
- end
109
-
110
- it "its column should not be case sensitive" do
111
- expect(User.columns.find{|column| column.name == "login"}).not_to be_case_sensitive
112
- end
113
-
114
- it "defines expression" do
115
- expect(@index.expression).to eq("lower((login)::text)")
116
- end
117
-
118
- it "doesn't define conditions" do
119
- expect(@index.conditions).to be_nil
120
- end
121
-
122
- end
123
-
124
-
125
- context "when index is partial" do
126
- before(:each) do
127
- migration.execute "CREATE INDEX users_login_index ON users(login) WHERE deleted_at IS NULL"
128
- User.reset_column_information
129
- @index = index_definition("login")
130
- end
131
-
132
- it "is included in User.indexes" do
133
- expect(User.indexes.select { |index| index.columns == ["login"] }.size).to eq(1)
134
- end
135
-
136
- it "is case_sensitive" do
137
- expect(@index).to be_case_sensitive
138
- end
139
-
140
- it "doesn't define expression" do
141
- expect(@index.expression).to be_nil
142
- end
143
-
144
- it "defines conditions" do
145
- expect(@index.conditions).to match %r{[(]?deleted_at IS NULL[)]?}
146
- end
147
-
148
- end if ::ActiveRecord::Migration.supports_partial_indexes?
149
-
150
- context "when index contains expression", :postgresql => :only do
151
- before(:each) do
152
- migration.execute "CREATE INDEX users_login_index ON users (extract(EPOCH from deleted_at)) WHERE deleted_at IS NULL"
153
- User.reset_column_information
154
- @index = User.indexes.detect { |i| i.expression.present? }
155
- end
156
-
157
- it "exists" do
158
- expect(@index).not_to be_nil
159
- end
160
-
161
- it "doesnt have columns defined" do
162
- expect(@index.columns).to be_empty
163
- end
164
-
165
- it "is case_sensitive" do
166
- expect(@index).to be_case_sensitive
167
- end
168
-
169
- it "defines expression" do
170
- expect(@index.expression).to eq("date_part('epoch'::text, deleted_at)")
171
- end
172
-
173
- it "defines conditions" do
174
- expect(@index.conditions).to eq("(deleted_at IS NULL)")
175
- end
176
-
177
- end
178
-
179
- context "when index has a non-btree type", :postgresql => :only do
180
- before(:each) do
181
- migration.execute "CREATE INDEX users_login_index ON users USING hash(login)"
182
- User.reset_column_information
183
- @index = User.indexes.detect { |i| i.name == "users_login_index" }
184
- end
185
-
186
- it "exists" do
187
- expect(@index).not_to be_nil
188
- end
189
-
190
- it "defines kind" do
191
- expect(@index.kind).to eq("hash")
192
- end
193
-
194
- it "does not define expression" do
195
- expect(@index.expression).to be_nil
196
- end
197
-
198
- it "does not define order" do
199
- expect(@index.orders).to be_blank
200
- end
201
- end
202
-
203
-
204
-
205
- protected
206
- def index_definition(column_names)
207
- User.indexes.detect { |index| index.columns == Array(column_names) }
208
- end
209
-
210
-
211
- end
@@ -1,249 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
-
3
- describe "index" do
4
-
5
- let(:migration) { ::ActiveRecord::Migration }
6
- let(:connection) { ::ActiveRecord::Base.connection }
7
-
8
- describe "add_index" do
9
-
10
- before(:each) do
11
- connection.tables.each do |table| connection.drop_table table, cascade: true end
12
-
13
- define_schema(:auto_create => false) do
14
- create_table :users, :force => true do |t|
15
- t.string :login
16
- t.text :address
17
- t.datetime :deleted_at
18
- end
19
-
20
- create_table :posts, :force => true do |t|
21
- t.text :body
22
- t.integer :user_id
23
- t.integer :author_id
24
- end
25
-
26
- create_table :comments, :force => true do |t|
27
- t.text :body
28
- t.integer :post_id
29
- t.foreign_key :post_id, :posts, :id
30
- end
31
- end
32
- class User < ::ActiveRecord::Base ; end
33
- class Post < ::ActiveRecord::Base ; end
34
- class Comment < ::ActiveRecord::Base ; end
35
- end
36
-
37
-
38
- after(:each) do
39
- migration.suppress_messages do
40
- migration.remove_index(:users, :name => @index.name) if (@index ||= nil)
41
- end
42
- end
43
-
44
- it "should create index when called without additional options" do
45
- add_index(:users, :login)
46
- expect(index_for(:login)).not_to be_nil
47
- end
48
-
49
- it "should create unique index" do
50
- add_index(:users, :login, :unique => true)
51
- expect(index_for(:login).unique).to eq(true)
52
- end
53
-
54
- it "should assign given name" do
55
- add_index(:users, :login, :name => 'users_login_index')
56
- expect(index_for(:login).name).to eq('users_login_index')
57
- end
58
-
59
- it "should assign order", :mysql => :skip do
60
- add_index(:users, [:login, :deleted_at], :order => {:login => :desc, :deleted_at => :asc})
61
- expect(index_for([:login, :deleted_at]).orders).to eq({"login" => :desc, "deleted_at" => :asc})
62
- end
63
-
64
- it "should respect algorithm: :concurrently", :postgresql => :only do
65
- expect(connection).to receive(:execute).with(/CREATE INDEX CONCURRENTLY/)
66
- add_index(:users, :login, :algorithm => :concurrently)
67
- end if ActiveRecord::VERSION::MAJOR > 3
68
-
69
- context "for duplicate index" do
70
- it "should not complain if the index is the same" do
71
- add_index(:users, :login)
72
- expect(index_for(:login)).not_to be_nil
73
- expect(ActiveRecord::Base.logger).to receive(:warn).with(/login.*Skipping/)
74
- expect { add_index(:users, :login) }.to_not raise_error
75
- expect(index_for(:login)).not_to be_nil
76
- end
77
- it "should complain if the index is different" do
78
- add_index(:users, :login, :unique => true)
79
- expect(index_for(:login)).not_to be_nil
80
- expect { add_index(:users, :login) }.to raise_error
81
- expect(index_for(:login)).not_to be_nil
82
- end
83
- end
84
-
85
- context "extra features", :postgresql => :only do
86
-
87
- it "should assign conditions" do
88
- add_index(:users, :login, :conditions => 'deleted_at IS NULL')
89
- expect(index_for(:login).conditions).to eq('(deleted_at IS NULL)')
90
- end
91
-
92
- it "should assign expression, conditions and kind" do
93
- add_index(:users, :expression => "USING hash (upper(login)) WHERE deleted_at IS NULL", :name => 'users_login_index')
94
- @index = User.indexes.detect { |i| i.expression.present? }
95
- expect(@index.expression).to eq("upper((login)::text)")
96
- expect(@index.conditions).to eq("(deleted_at IS NULL)")
97
- expect(@index.kind).to eq("hash")
98
- end
99
-
100
- it "should allow to specify expression, conditions and kind separately" do
101
- add_index(:users, :kind => "hash", :expression => "upper(login)", :conditions => "deleted_at IS NULL", :name => 'users_login_index')
102
- @index = User.indexes.detect { |i| i.expression.present? }
103
- expect(@index.expression).to eq("upper((login)::text)")
104
- expect(@index.conditions).to eq("(deleted_at IS NULL)")
105
- expect(@index.kind).to eq("hash")
106
- end
107
-
108
- it "should allow to specify kind" do
109
- add_index(:users, :login, :kind => "hash")
110
- expect(index_for(:login).kind).to eq('hash')
111
- end
112
-
113
- it "should assign operator_class" do
114
- add_index(:users, :login, :operator_class => 'varchar_pattern_ops')
115
- expect(index_for(:login).operator_classes).to eq({"login" => 'varchar_pattern_ops'})
116
- end
117
-
118
- it "should assign multiple operator_classes" do
119
- add_index(:users, [:login, :address], :operator_class => {:login => 'varchar_pattern_ops', :address => 'text_pattern_ops'})
120
- expect(index_for([:login, :address]).operator_classes).to eq({"login" => 'varchar_pattern_ops', "address" => 'text_pattern_ops'})
121
- end
122
-
123
- it "should allow to specify actual expression only" do
124
- add_index(:users, :expression => "upper(login)", :name => 'users_login_index')
125
- @index = User.indexes.detect { |i| i.name == 'users_login_index' }
126
- expect(@index.expression).to eq("upper((login)::text)")
127
- end
128
-
129
- it "should raise if no column given and expression is missing" do
130
- expect { add_index(:users, :name => 'users_login_index') }.to raise_error(ArgumentError, /expression/)
131
- end
132
-
133
- it "should raise if expression without name is given" do
134
- expect { add_index(:users, :expression => "USING btree (login)") }.to raise_error(ArgumentError, /name/)
135
- end
136
-
137
- it "should raise if expression is given and case_sensitive is false" do
138
- expect { add_index(:users, :name => 'users_login_index', :expression => "USING btree (login)", :case_sensitive => false) }.to raise_error(ArgumentError, /use LOWER/i)
139
- end
140
-
141
- end
142
-
143
- protected
144
-
145
- def index_for(column_names)
146
- @index = User.indexes.detect { |i| i.columns == Array(column_names).collect(&:to_s) }
147
- end
148
-
149
- end
150
-
151
- describe "remove_index" do
152
-
153
- before(:each) do
154
- connection.tables.each do |table| connection.drop_table table, cascade: true end
155
- define_schema(:auto_create => false) do
156
- create_table :users, :force => true do |t|
157
- t.string :login
158
- t.datetime :deleted_at
159
- end
160
- end
161
- class User < ::ActiveRecord::Base ; end
162
- end
163
-
164
-
165
- it "removes index by column name (symbols)" do
166
- add_index :users, :login
167
- expect(User.indexes.length).to eq(1)
168
- remove_index :users, :login
169
- expect(User.indexes.length).to eq(0)
170
- end
171
-
172
- it "removes index by column name (symbols)" do
173
- add_index :users, :login
174
- expect(User.indexes.length).to eq(1)
175
- remove_index 'users', 'login'
176
- expect(User.indexes.length).to eq(0)
177
- end
178
-
179
- it "removes multi-column index by column names (symbols)" do
180
- add_index :users, [:login, :deleted_at]
181
- expect(User.indexes.length).to eq(1)
182
- remove_index :users, [:login, :deleted_at]
183
- expect(User.indexes.length).to eq(0)
184
- end
185
-
186
- it "removes multi-column index by column names (strings)" do
187
- add_index 'users', [:login, :deleted_at]
188
- expect(User.indexes.length).to eq(1)
189
- remove_index 'users', ['login', 'deleted_at']
190
- expect(User.indexes.length).to eq(0)
191
- end
192
-
193
- it "removes index using column option" do
194
- add_index :users, :login
195
- expect(User.indexes.length).to eq(1)
196
- remove_index :users, column: :login
197
- expect(User.indexes.length).to eq(0)
198
- end
199
-
200
- it "removes index if_exists" do
201
- add_index :users, :login
202
- expect(User.indexes.length).to eq(1)
203
- remove_index :users, :login, :if_exists => true
204
- expect(User.indexes.length).to eq(0)
205
- end
206
-
207
- it "removes multi-column index if exists" do
208
- add_index :users, [:login, :deleted_at]
209
- expect(User.indexes.length).to eq(1)
210
- remove_index :users, [:login, :deleted_at], :if_exists => true
211
- expect(User.indexes.length).to eq(0)
212
- end
213
-
214
- it "removes index if_exists using column option" do
215
- add_index :users, :login
216
- expect(User.indexes.length).to eq(1)
217
- remove_index :users, column: :login, :if_exists => true
218
- expect(User.indexes.length).to eq(0)
219
- end
220
-
221
- it "raises exception if doesn't exist" do
222
- expect {
223
- remove_index :users, :login
224
- }.to raise_error
225
- end
226
-
227
- it "doesn't raise exception with :if_exists" do
228
- expect {
229
- remove_index :users, :login, :if_exists => true
230
- }.to_not raise_error
231
- end
232
- end
233
-
234
- protected
235
- def add_index(*args)
236
- migration.suppress_messages do
237
- migration.add_index(*args)
238
- end
239
- User.reset_column_information
240
- end
241
-
242
- def remove_index(*args)
243
- migration.suppress_messages do
244
- migration.remove_index(*args)
245
- end
246
- User.reset_column_information
247
- end
248
-
249
- end