schema_plus_indexes 0.1.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 +7 -0
- data/.gitignore +8 -0
- data/.travis.yml +19 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +99 -0
- data/Rakefile +9 -0
- data/gemfiles/Gemfile.base +8 -0
- data/gemfiles/rails-4.2/Gemfile.base +3 -0
- data/gemfiles/rails-4.2/Gemfile.mysql2 +10 -0
- data/gemfiles/rails-4.2/Gemfile.postgresql +10 -0
- data/gemfiles/rails-4.2/Gemfile.sqlite3 +10 -0
- data/lib/schema_plus_indexes.rb +11 -0
- data/lib/schema_plus_indexes/active_record/base.rb +29 -0
- data/lib/schema_plus_indexes/active_record/connection_adapters/abstract_adapter.rb +23 -0
- data/lib/schema_plus_indexes/active_record/connection_adapters/index_definition.rb +42 -0
- data/lib/schema_plus_indexes/middleware/dumper.rb +43 -0
- data/lib/schema_plus_indexes/middleware/migration.rb +65 -0
- data/lib/schema_plus_indexes/middleware/model.rb +17 -0
- data/lib/schema_plus_indexes/middleware/sqlite3.rb +25 -0
- data/lib/schema_plus_indexes/version.rb +3 -0
- data/schema_dev.yml +9 -0
- data/schema_plus_indexes.gemspec +29 -0
- data/spec/index_definition_spec.rb +102 -0
- data/spec/index_spec.rb +180 -0
- data/spec/migration_spec.rb +188 -0
- data/spec/named_schema_spec.rb +60 -0
- data/spec/sanity_spec.rb +13 -0
- data/spec/schema_dumper_spec.rb +118 -0
- data/spec/spec_helper.rb +34 -0
- data/spec/support/matchers/have_index.rb +60 -0
- metadata +194 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
module SchemaPlusIndexes
|
2
|
+
module Middleware
|
3
|
+
module Model
|
4
|
+
|
5
|
+
def self.insert
|
6
|
+
SchemaMonkey::Middleware::Model::ResetColumnInformation.append ResetColumnInformation
|
7
|
+
end
|
8
|
+
|
9
|
+
class ResetColumnInformation < SchemaMonkey::Middleware::Base
|
10
|
+
def call(env)
|
11
|
+
continue env
|
12
|
+
env.model.reset_index_information
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module SchemaPlusIndexes
|
2
|
+
module Middleware
|
3
|
+
module Sqlite3
|
4
|
+
def self.insert
|
5
|
+
SchemaMonkey::Middleware::Query::Indexes.append LookupExtensions
|
6
|
+
end
|
7
|
+
|
8
|
+
class LookupExtensions < SchemaMonkey::Middleware::Base
|
9
|
+
def call(env)
|
10
|
+
continue env
|
11
|
+
indexes = Hash[env.index_definitions.map{ |d| [d.name, d] }]
|
12
|
+
|
13
|
+
env.connection.exec_query("SELECT name, sql FROM sqlite_master WHERE type = 'index'").map do |row|
|
14
|
+
if (desc_columns = row['sql'].scan(/['"`]?(\w+)['"`]? DESC\b/).flatten).any?
|
15
|
+
index = indexes[row['name']]
|
16
|
+
index.orders = Hash[index.columns.map {|column| [column, desc_columns.include?(column) ? :desc : :asc]}]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
env.index_definitions
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/schema_dev.yml
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'schema_plus_indexes/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "schema_plus_indexes"
|
8
|
+
spec.version = SchemaPlusIndexes::VERSION
|
9
|
+
spec.authors = ["ronen barzel"]
|
10
|
+
spec.email = ["ronen@barzel.org"]
|
11
|
+
spec.summary = %q{Adds shorthands and conveniences to ActiveRecord's handling of indexes}
|
12
|
+
spec.homepage = "https://github.com/SchemaPlus/schema_plus_indexes"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0")
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_dependency "activerecord", "~> 4.2"
|
21
|
+
spec.add_dependency "schema_monkey", "~> 0.2"
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
24
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
25
|
+
spec.add_development_dependency "rspec", "~> 3.0.0"
|
26
|
+
spec.add_development_dependency "schema_dev", "~> 2.0"
|
27
|
+
spec.add_development_dependency "simplecov"
|
28
|
+
spec.add_development_dependency "simplecov-gem-profile"
|
29
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require '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
|
+
end
|
22
|
+
class User < ::ActiveRecord::Base ; end
|
23
|
+
class Post < ::ActiveRecord::Base ; end
|
24
|
+
end
|
25
|
+
|
26
|
+
around(:each) do |example|
|
27
|
+
migration.suppress_messages do
|
28
|
+
example.run
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
after(:each) do
|
33
|
+
migration.remove_index :users, :name => 'users_login_index' if migration.index_name_exists? :users, 'users_login_index', true
|
34
|
+
end
|
35
|
+
|
36
|
+
context "when index is multicolumn" do
|
37
|
+
before(:each) do
|
38
|
+
migration.execute "CREATE INDEX users_login_index ON users (login, deleted_at)"
|
39
|
+
User.reset_column_information
|
40
|
+
@index = index_definition(%w[login deleted_at])
|
41
|
+
end
|
42
|
+
|
43
|
+
it "is included in User.indexes" do
|
44
|
+
expect(@index).not_to be_nil
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should not crash on equality test with nil" do
|
50
|
+
index = ActiveRecord::ConnectionAdapters::IndexDefinition.new(:table, :column)
|
51
|
+
expect{index == nil}.to_not raise_error
|
52
|
+
expect(index == nil).to be false
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
context "when index is ordered", :mysql => :skip do
|
57
|
+
|
58
|
+
quotes = [
|
59
|
+
["unquoted", ''],
|
60
|
+
["double-quoted", '"'],
|
61
|
+
]
|
62
|
+
quotes += [
|
63
|
+
["single-quoted", "'"],
|
64
|
+
["back-quoted", '`']
|
65
|
+
] if SchemaDev::Rspec::Helpers.sqlite3?
|
66
|
+
|
67
|
+
quotes.each do |quotename, quote|
|
68
|
+
it "index definition includes orders for #{quotename} columns" do
|
69
|
+
migration.execute "CREATE INDEX users_login_index ON users (#{quote}login#{quote} DESC, #{quote}deleted_at#{quote} ASC)"
|
70
|
+
User.reset_column_information
|
71
|
+
index = index_definition(%w[login deleted_at])
|
72
|
+
expect(index.orders).to eq({"login" => :desc, "deleted_at" => :asc})
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context "when index is partial" do
|
79
|
+
before(:each) do
|
80
|
+
migration.execute "CREATE INDEX users_login_index ON users(login) WHERE deleted_at IS NULL"
|
81
|
+
User.reset_column_information
|
82
|
+
@index = index_definition("login")
|
83
|
+
end
|
84
|
+
|
85
|
+
it "is included in User.indexes" do
|
86
|
+
expect(User.indexes.select { |index| index.columns == ["login"] }.size).to eq(1)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "defines where" do
|
90
|
+
expect(@index.where).to match %r{[(]?deleted_at IS NULL[)]?}
|
91
|
+
end
|
92
|
+
|
93
|
+
end if ::ActiveRecord::Migration.supports_partial_index?
|
94
|
+
|
95
|
+
|
96
|
+
protected
|
97
|
+
def index_definition(column_names)
|
98
|
+
User.indexes.detect { |index| index.columns == Array(column_names) }
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
end
|
data/spec/index_spec.rb
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
require '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
|
+
end
|
27
|
+
class User < ::ActiveRecord::Base ; end
|
28
|
+
class Post < ::ActiveRecord::Base ; end
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
after(:each) do
|
33
|
+
migration.suppress_messages do
|
34
|
+
migration.remove_index(:users, :name => @index.name) if (@index ||= nil)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should create index when called without additional options" do
|
39
|
+
add_index(:users, :login)
|
40
|
+
expect(index_for(:login)).not_to be_nil
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should create unique index" do
|
44
|
+
add_index(:users, :login, :unique => true)
|
45
|
+
expect(index_for(:login).unique).to eq(true)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should assign given name" do
|
49
|
+
add_index(:users, :login, :name => 'users_login_index')
|
50
|
+
expect(index_for(:login).name).to eq('users_login_index')
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should assign order", :mysql => :skip do
|
54
|
+
add_index(:users, [:login, :deleted_at], :order => {:login => :desc, :deleted_at => :asc})
|
55
|
+
expect(index_for([:login, :deleted_at]).orders).to eq({"login" => :desc, "deleted_at" => :asc})
|
56
|
+
end
|
57
|
+
|
58
|
+
context "for duplicate index" do
|
59
|
+
it "should not complain if the index is the same" do
|
60
|
+
add_index(:users, :login)
|
61
|
+
expect(index_for(:login)).not_to be_nil
|
62
|
+
expect(ActiveRecord::Base.logger).to receive(:warn).with(/login.*Skipping/)
|
63
|
+
expect { add_index(:users, :login) }.to_not raise_error
|
64
|
+
expect(index_for(:login)).not_to be_nil
|
65
|
+
end
|
66
|
+
it "should complain if the index is different" do
|
67
|
+
add_index(:users, :login, :unique => true)
|
68
|
+
expect(index_for(:login)).not_to be_nil
|
69
|
+
expect { add_index(:users, :login) }.to raise_error
|
70
|
+
expect(index_for(:login)).not_to be_nil
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
protected
|
75
|
+
|
76
|
+
def index_for(column_names)
|
77
|
+
@index = User.indexes.detect { |i| i.columns == Array(column_names).collect(&:to_s) }
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "remove_index" do
|
83
|
+
|
84
|
+
before(:each) do
|
85
|
+
connection.tables.each do |table| connection.drop_table table, cascade: true end
|
86
|
+
define_schema(:auto_create => false) do
|
87
|
+
create_table :users, :force => true do |t|
|
88
|
+
t.string :login
|
89
|
+
t.datetime :deleted_at
|
90
|
+
end
|
91
|
+
end
|
92
|
+
class User < ::ActiveRecord::Base ; end
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
it "removes index by column name (symbols)" do
|
97
|
+
add_index :users, :login
|
98
|
+
expect(User.indexes.length).to eq(1)
|
99
|
+
remove_index :users, :login
|
100
|
+
expect(User.indexes.length).to eq(0)
|
101
|
+
end
|
102
|
+
|
103
|
+
it "removes index by column name (symbols)" do
|
104
|
+
add_index :users, :login
|
105
|
+
expect(User.indexes.length).to eq(1)
|
106
|
+
remove_index 'users', 'login'
|
107
|
+
expect(User.indexes.length).to eq(0)
|
108
|
+
end
|
109
|
+
|
110
|
+
it "removes multi-column index by column names (symbols)" do
|
111
|
+
add_index :users, [:login, :deleted_at]
|
112
|
+
expect(User.indexes.length).to eq(1)
|
113
|
+
remove_index :users, [:login, :deleted_at]
|
114
|
+
expect(User.indexes.length).to eq(0)
|
115
|
+
end
|
116
|
+
|
117
|
+
it "removes multi-column index by column names (strings)" do
|
118
|
+
add_index 'users', [:login, :deleted_at]
|
119
|
+
expect(User.indexes.length).to eq(1)
|
120
|
+
remove_index 'users', ['login', 'deleted_at']
|
121
|
+
expect(User.indexes.length).to eq(0)
|
122
|
+
end
|
123
|
+
|
124
|
+
it "removes index using column option" do
|
125
|
+
add_index :users, :login
|
126
|
+
expect(User.indexes.length).to eq(1)
|
127
|
+
remove_index :users, column: :login
|
128
|
+
expect(User.indexes.length).to eq(0)
|
129
|
+
end
|
130
|
+
|
131
|
+
it "removes index if_exists" do
|
132
|
+
add_index :users, :login
|
133
|
+
expect(User.indexes.length).to eq(1)
|
134
|
+
remove_index :users, :login, :if_exists => true
|
135
|
+
expect(User.indexes.length).to eq(0)
|
136
|
+
end
|
137
|
+
|
138
|
+
it "removes multi-column index if exists" do
|
139
|
+
add_index :users, [:login, :deleted_at]
|
140
|
+
expect(User.indexes.length).to eq(1)
|
141
|
+
remove_index :users, [:login, :deleted_at], :if_exists => true
|
142
|
+
expect(User.indexes.length).to eq(0)
|
143
|
+
end
|
144
|
+
|
145
|
+
it "removes index if_exists using column option" do
|
146
|
+
add_index :users, :login
|
147
|
+
expect(User.indexes.length).to eq(1)
|
148
|
+
remove_index :users, column: :login, :if_exists => true
|
149
|
+
expect(User.indexes.length).to eq(0)
|
150
|
+
end
|
151
|
+
|
152
|
+
it "raises exception if doesn't exist" do
|
153
|
+
expect {
|
154
|
+
remove_index :users, :login
|
155
|
+
}.to raise_error
|
156
|
+
end
|
157
|
+
|
158
|
+
it "doesn't raise exception with :if_exists" do
|
159
|
+
expect {
|
160
|
+
remove_index :users, :login, :if_exists => true
|
161
|
+
}.to_not raise_error
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
protected
|
166
|
+
def add_index(*args)
|
167
|
+
migration.suppress_messages do
|
168
|
+
migration.add_index(*args)
|
169
|
+
end
|
170
|
+
User.reset_column_information
|
171
|
+
end
|
172
|
+
|
173
|
+
def remove_index(*args)
|
174
|
+
migration.suppress_messages do
|
175
|
+
migration.remove_index(*args)
|
176
|
+
end
|
177
|
+
User.reset_column_information
|
178
|
+
end
|
179
|
+
|
180
|
+
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe ActiveRecord::Migration do
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
define_schema(:auto_create => true) do
|
8
|
+
|
9
|
+
create_table :users, :force => true do |t|
|
10
|
+
t.string :login, :index => { :unique => true }
|
11
|
+
end
|
12
|
+
|
13
|
+
create_table :members, :force => true do |t|
|
14
|
+
t.string :login
|
15
|
+
end
|
16
|
+
|
17
|
+
create_table :comments, :force => true do |t|
|
18
|
+
t.string :content
|
19
|
+
t.integer :user
|
20
|
+
t.integer :user_id
|
21
|
+
end
|
22
|
+
|
23
|
+
create_table :posts, :force => true do |t|
|
24
|
+
t.string :content
|
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
|
+
context "when table is created" do
|
33
|
+
|
34
|
+
before(:each) do
|
35
|
+
@model = Post
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should create an index if specified on column" do
|
39
|
+
recreate_table(@model) do |t|
|
40
|
+
t.integer :state, :index => true
|
41
|
+
end
|
42
|
+
expect(@model).to have_index.on(:state)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should create a unique index if specified on column" do
|
46
|
+
recreate_table(@model) do |t|
|
47
|
+
t.integer :state, :index => { :unique => true }
|
48
|
+
end
|
49
|
+
expect(@model).to have_unique_index.on(:state)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should create a unique index if specified on column using shorthand" do
|
53
|
+
recreate_table(@model) do |t|
|
54
|
+
t.integer :state, :index => :unique
|
55
|
+
end
|
56
|
+
expect(@model).to have_unique_index.on(:state)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should pass index length option properly", :mysql => :only do
|
60
|
+
recreate_table(@model) do |t|
|
61
|
+
t.string :foo
|
62
|
+
t.string :bar, :index => { :with => :foo, :length => { :foo => 8, :bar => 12 }}
|
63
|
+
end
|
64
|
+
index = @model.indexes.first
|
65
|
+
expect(Hash[index.columns.zip(index.lengths.map(&:to_i))]).to eq({ "foo" => 8, "bar" => 12})
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should create an index if specified explicitly" do
|
69
|
+
recreate_table(@model) do |t|
|
70
|
+
t.integer :state
|
71
|
+
t.index :state
|
72
|
+
end
|
73
|
+
expect(@model).to have_index.on(:state)
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should create a unique index if specified explicitly" do
|
77
|
+
recreate_table(@model) do |t|
|
78
|
+
t.integer :state
|
79
|
+
t.index :state, :unique => true
|
80
|
+
end
|
81
|
+
expect(@model).to have_unique_index.on(:state)
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should create a multiple-column index if specified" do
|
85
|
+
recreate_table(@model) do |t|
|
86
|
+
t.integer :city
|
87
|
+
t.integer :state, :index => { :with => :city }
|
88
|
+
end
|
89
|
+
expect(@model).to have_index.on([:state, :city])
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should create the index without modifying the input hash" do
|
93
|
+
hash = { :with => :foo, :length => { :foo => 8, :bar => 12 }}
|
94
|
+
hash_original = hash.dup
|
95
|
+
recreate_table(@model) do |t|
|
96
|
+
t.string :foo
|
97
|
+
t.string :bar, :index => hash
|
98
|
+
end
|
99
|
+
expect(hash).to eq(hash_original)
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
context "when table is changed" do
|
105
|
+
before(:each) do
|
106
|
+
@model = Post
|
107
|
+
end
|
108
|
+
[false, true].each do |bulk|
|
109
|
+
suffix = bulk ? ' with :bulk option' : ""
|
110
|
+
|
111
|
+
it "should create an index if specified on column"+suffix do
|
112
|
+
change_table(@model, :bulk => bulk) do |t|
|
113
|
+
t.integer :state, :index => true
|
114
|
+
end
|
115
|
+
expect(@model).to have_index.on(:state)
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context "when column is added", :sqlite3 => :skip do
|
122
|
+
|
123
|
+
before(:each) do
|
124
|
+
@model = Comment
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should create an index" do
|
128
|
+
add_column(:slug, :string, :index => true) do
|
129
|
+
expect(@model).to have_index.on(:slug)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should create an index if specified" do
|
134
|
+
add_column(:post_id, :integer, :index => true) do
|
135
|
+
expect(@model).to have_index.on(:post_id)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should create a unique index if specified" do
|
140
|
+
add_column(:post_id, :integer, :index => { :unique => true }) do
|
141
|
+
expect(@model).to have_unique_index.on(:post_id)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should create a unique index if specified by shorthand" do
|
146
|
+
add_column(:post_id, :integer, :index => :unique) do
|
147
|
+
expect(@model).to have_unique_index.on(:post_id)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should allow custom name for index" do
|
152
|
+
index_name = 'comments_post_id_unique_index'
|
153
|
+
add_column(:post_id, :integer, :index => { :unique => true, :name => index_name }) do
|
154
|
+
expect(@model).to have_unique_index(:name => index_name).on(:post_id)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
protected
|
159
|
+
|
160
|
+
def add_column(column_name, *args)
|
161
|
+
table = @model.table_name
|
162
|
+
ActiveRecord::Migration.suppress_messages do
|
163
|
+
ActiveRecord::Migration.add_column(table, column_name, *args)
|
164
|
+
@model.reset_column_information
|
165
|
+
yield if block_given?
|
166
|
+
ActiveRecord::Migration.remove_column(table, column_name)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
|
173
|
+
def recreate_table(model, opts={}, &block)
|
174
|
+
ActiveRecord::Migration.suppress_messages do
|
175
|
+
ActiveRecord::Migration.create_table model.table_name, opts.merge(:force => true), &block
|
176
|
+
end
|
177
|
+
model.reset_column_information
|
178
|
+
end
|
179
|
+
|
180
|
+
def change_table(model, opts={}, &block)
|
181
|
+
ActiveRecord::Migration.suppress_messages do
|
182
|
+
ActiveRecord::Migration.change_table model.table_name, opts, &block
|
183
|
+
end
|
184
|
+
model.reset_column_information
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
188
|
+
|