schema_plus 1.8.9 → 2.0.0.pre1
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 +4 -4
- data/.travis.yml +1 -47
- data/CHANGELOG.md +0 -35
- data/README.md +73 -107
- data/Rakefile +7 -10
- data/TODO.md +51 -0
- data/gemfiles/Gemfile.base +2 -0
- data/lib/schema_column_plus.rb +7 -0
- data/lib/{schema_plus → schema_column_plus}/active_record/connection_adapters/column.rb +13 -11
- data/lib/schema_column_plus/middleware/model.rb +22 -0
- data/lib/schema_db_default.rb +13 -0
- data/lib/{schema_plus → schema_db_default}/active_record/attribute.rb +4 -4
- data/lib/schema_db_default/db_default.rb +17 -0
- data/lib/schema_db_default/middleware.rb +30 -0
- data/lib/schema_default_expr.rb +32 -0
- data/lib/schema_default_expr/active_record/connection_adapters/mysql_adapter.rb +17 -0
- data/lib/schema_default_expr/active_record/connection_adapters/postgresql_adapter.rb +18 -0
- data/lib/schema_default_expr/active_record/connection_adapters/sqlite3_adapter.rb +35 -0
- data/lib/schema_default_expr/middleware.rb +54 -0
- data/lib/schema_pg_enums.rb +6 -0
- data/lib/schema_pg_enums/active_record.rb +69 -0
- data/lib/schema_pg_enums/middleware.rb +23 -0
- data/lib/schema_plus.rb +17 -45
- data/lib/schema_plus/active_record/base.rb +6 -23
- data/lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb +80 -181
- data/lib/schema_plus/active_record/connection_adapters/foreign_key_definition.rb +78 -99
- data/lib/schema_plus/active_record/connection_adapters/mysql_adapter.rb +34 -114
- data/lib/schema_plus/active_record/connection_adapters/postgresql_adapter.rb +16 -370
- data/lib/schema_plus/active_record/connection_adapters/schema_statements.rb +1 -67
- data/lib/schema_plus/active_record/connection_adapters/sqlite3_adapter.rb +18 -112
- data/lib/schema_plus/active_record/connection_adapters/table_definition.rb +14 -116
- data/lib/schema_plus/active_record/migration/command_recorder.rb +8 -59
- data/lib/schema_plus/middleware/dumper.rb +94 -0
- data/lib/schema_plus/middleware/migration.rb +167 -0
- data/lib/schema_plus/middleware/model.rb +17 -0
- data/lib/schema_plus/version.rb +1 -1
- data/lib/schema_plus_tables.rb +15 -0
- data/lib/schema_plus_tables/active_record/connection_adapters/abstract_adapter.rb +20 -0
- data/lib/schema_plus_tables/active_record/connection_adapters/mysql_adapter.rb +25 -0
- data/lib/schema_plus_tables/active_record/connection_adapters/postgresql_adapter.rb +13 -0
- data/lib/schema_plus_tables/active_record/connection_adapters/sqlite3_adapter.rb +12 -0
- data/lib/schema_views.rb +16 -0
- data/lib/schema_views/active_record/connection_adapters/abstract_adapter.rb +41 -0
- data/lib/schema_views/active_record/connection_adapters/mysql_adapter.rb +30 -0
- data/lib/schema_views/active_record/connection_adapters/postgresql_adapter.rb +31 -0
- data/lib/schema_views/active_record/connection_adapters/sqlite3_adapter.rb +18 -0
- data/lib/schema_views/middleware.rb +47 -0
- data/schema_dev.yml +1 -31
- data/schema_plus.gemspec +11 -9
- data/spec/foreign_key_definition_spec.rb +7 -7
- data/spec/foreign_key_spec.rb +63 -48
- data/spec/migration_spec.rb +58 -203
- data/spec/named_schemas_spec.rb +5 -88
- data/spec/{column_spec.rb → schema_column_plus/column_spec.rb} +26 -48
- data/spec/schema_db_default/column_spec.rb +58 -0
- data/spec/{column_default_spec.rb → schema_default_expr/column_default_spec.rb} +1 -2
- data/spec/schema_default_expr/schema_dumper_spec.rb +116 -0
- data/spec/schema_dumper_spec.rb +22 -327
- data/spec/{enum_spec.rb → schema_pg_enums/enum_spec.rb} +1 -1
- data/spec/schema_pg_enums/schema_dumper_spec.rb +37 -0
- data/spec/schema_views/named_schemas_spec.rb +97 -0
- data/spec/{views_spec.rb → schema_views/views_spec.rb} +1 -1
- data/spec/spec_helper.rb +2 -1
- data/spec/support/matchers/reference.rb +11 -12
- metadata +104 -57
- data/gemfiles/rails-3.2/Gemfile.base +0 -3
- data/gemfiles/rails-3.2/Gemfile.mysql +0 -10
- data/gemfiles/rails-3.2/Gemfile.mysql2 +0 -10
- data/gemfiles/rails-3.2/Gemfile.postgresql +0 -10
- data/gemfiles/rails-3.2/Gemfile.sqlite3 +0 -10
- data/gemfiles/rails-4.0/Gemfile.base +0 -3
- data/gemfiles/rails-4.0/Gemfile.mysql2 +0 -10
- data/gemfiles/rails-4.0/Gemfile.postgresql +0 -10
- data/gemfiles/rails-4.0/Gemfile.sqlite3 +0 -10
- data/gemfiles/rails-4.1/Gemfile.base +0 -3
- data/gemfiles/rails-4.1/Gemfile.mysql2 +0 -10
- data/gemfiles/rails-4.1/Gemfile.postgresql +0 -10
- data/gemfiles/rails-4.1/Gemfile.sqlite3 +0 -10
- data/lib/schema_plus/active_record/column_options_handler.rb +0 -117
- data/lib/schema_plus/active_record/connection_adapters/index_definition.rb +0 -70
- data/lib/schema_plus/active_record/db_default.rb +0 -19
- data/lib/schema_plus/active_record/foreign_keys.rb +0 -137
- data/lib/schema_plus/active_record/schema_dumper.rb +0 -171
- data/lib/schema_plus/railtie.rb +0 -20
- data/spec/index_definition_spec.rb +0 -211
- data/spec/index_spec.rb +0 -249
@@ -0,0 +1,31 @@
|
|
1
|
+
module SchemaViews
|
2
|
+
module ActiveRecord
|
3
|
+
module ConnectionAdapters
|
4
|
+
module PostgresqlAdapter
|
5
|
+
|
6
|
+
def views(name = nil) #:nodoc:
|
7
|
+
sql = <<-SQL
|
8
|
+
SELECT viewname
|
9
|
+
FROM pg_views
|
10
|
+
WHERE schemaname = ANY (current_schemas(false))
|
11
|
+
AND viewname NOT LIKE 'pg\_%'
|
12
|
+
SQL
|
13
|
+
sql += " AND schemaname != 'postgis'" if adapter_name == 'PostGIS'
|
14
|
+
query(sql, name).map { |row| row[0] }
|
15
|
+
end
|
16
|
+
|
17
|
+
def view_definition(view_name, name = nil) #:nodoc:
|
18
|
+
result = query(<<-SQL, name)
|
19
|
+
SELECT pg_get_viewdef(oid)
|
20
|
+
FROM pg_class
|
21
|
+
WHERE relkind = 'v'
|
22
|
+
AND relname = '#{view_name}'
|
23
|
+
SQL
|
24
|
+
row = result.first
|
25
|
+
row.first.chomp(';') unless row.nil?
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module SchemaViews
|
2
|
+
module ActiveRecord
|
3
|
+
module ConnectionAdapters
|
4
|
+
module Sqlite3Adapter
|
5
|
+
|
6
|
+
def views(name = nil)
|
7
|
+
execute("SELECT name FROM sqlite_master WHERE type='view'", name).collect{|row| row["name"]}
|
8
|
+
end
|
9
|
+
|
10
|
+
def view_definition(view_name, name = nil)
|
11
|
+
sql = execute("SELECT sql FROM sqlite_master WHERE type='view' AND name=#{quote(view_name)}", name).collect{|row| row["sql"]}.first
|
12
|
+
sql.sub(/^CREATE VIEW \S* AS\s+/im, '') unless sql.nil?
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module SchemaViews
|
2
|
+
module Middleware
|
3
|
+
def self.insert
|
4
|
+
SchemaMonkey::Middleware::Dumper::Tables.prepend DumpViews
|
5
|
+
end
|
6
|
+
module Mysql
|
7
|
+
def self.insert
|
8
|
+
SchemaMonkey::Middleware::Query::Tables.append FilterOutViews
|
9
|
+
end
|
10
|
+
end
|
11
|
+
module Sqlite3
|
12
|
+
def self.insert
|
13
|
+
SchemaMonkey::Middleware::Query::Tables.append FilterOutViews
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class FilterOutViews < SchemaMonkey::Middleware::Base
|
19
|
+
def call(env)
|
20
|
+
continue env
|
21
|
+
env.tables -= env.connection.views(env.query_name)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class DumpViews < SchemaMonkey::Middleware::Base
|
26
|
+
|
27
|
+
# quacks like a SchemaMonkey Dump::Table
|
28
|
+
class View < KeyStruct[:name, :definition]
|
29
|
+
def assemble(stream)
|
30
|
+
stream.puts(" create_view #{name.inspect}, #{definition.inspect}, :force => true\n")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def call(env)
|
35
|
+
continue env
|
36
|
+
|
37
|
+
re_view_referent = %r{(?:(?i)FROM|JOIN) \S*\b(\S+)\b}
|
38
|
+
env.connection.views.each do |view_name|
|
39
|
+
next if env.dumper.ignored?(view_name)
|
40
|
+
view = View.new(name: view_name, definition: env.connection.view_definition(view_name))
|
41
|
+
env.dump.tables[view.name] = view
|
42
|
+
env.dump.depends(view.name, view.definition.scan(re_view_referent).flatten)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
data/schema_dev.yml
CHANGED
@@ -1,39 +1,9 @@
|
|
1
1
|
ruby:
|
2
|
-
- jruby
|
3
2
|
- 1.9.3
|
4
|
-
- 2.1.
|
3
|
+
- 2.1.5
|
5
4
|
rails:
|
6
|
-
- 3.2
|
7
|
-
- 4.0
|
8
|
-
- 4.1
|
9
5
|
- 4.2
|
10
6
|
db:
|
11
|
-
- mysql
|
12
7
|
- mysql2
|
13
8
|
- sqlite3
|
14
9
|
- postgresql
|
15
|
-
exclude:
|
16
|
-
-
|
17
|
-
rails: 4.0
|
18
|
-
db: mysql
|
19
|
-
-
|
20
|
-
rails: 4.1
|
21
|
-
db: mysql
|
22
|
-
-
|
23
|
-
rails: 4.2
|
24
|
-
db: mysql
|
25
|
-
-
|
26
|
-
ruby: jruby
|
27
|
-
rails: 4.0
|
28
|
-
-
|
29
|
-
ruby: jruby
|
30
|
-
rails: 4.1
|
31
|
-
-
|
32
|
-
ruby: jruby
|
33
|
-
rails: 4.2
|
34
|
-
-
|
35
|
-
ruby: jruby
|
36
|
-
db: sqlite3
|
37
|
-
-
|
38
|
-
ruby: jruby
|
39
|
-
db: postgresql
|
data/schema_plus.gemspec
CHANGED
@@ -21,15 +21,17 @@ Gem::Specification.new do |s|
|
|
21
21
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
22
22
|
s.require_paths = ["lib"]
|
23
23
|
|
24
|
-
s.add_dependency
|
25
|
-
s.add_dependency
|
24
|
+
s.add_dependency "activerecord", ">= 3.2", "< 4.3"
|
25
|
+
s.add_dependency "valuable"
|
26
|
+
s.add_dependency "schema_monkey", "~> 0.1"
|
27
|
+
s.add_dependency "schema_plus_indexes", "~> 0.1"
|
28
|
+
s.add_dependency "schema_plus_pg_indexes", "~> 0.1"
|
26
29
|
|
27
|
-
s.add_development_dependency
|
28
|
-
s.add_development_dependency
|
29
|
-
s.add_development_dependency
|
30
|
-
s.add_development_dependency
|
31
|
-
s.add_development_dependency
|
32
|
-
s.add_development_dependency
|
33
|
-
s.add_development_dependency("its-it")
|
30
|
+
s.add_development_dependency "schema_dev", "~> 2.0", ">= 2.0.3"
|
31
|
+
s.add_development_dependency "rake"
|
32
|
+
s.add_development_dependency "rspec", "~> 3.0.0"
|
33
|
+
s.add_development_dependency "rdoc"
|
34
|
+
s.add_development_dependency "simplecov"
|
35
|
+
s.add_development_dependency "simplecov-gem-profile"
|
34
36
|
end
|
35
37
|
|
@@ -1,10 +1,10 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
describe "Foreign Key definition" do
|
4
4
|
|
5
5
|
let(:definition) {
|
6
|
-
options = {:name => "posts_user_fkey", :
|
7
|
-
|
6
|
+
options = {:name => "posts_user_fkey", :column => :user, :primary_key => :id}
|
7
|
+
::ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new(:posts, :users, options)
|
8
8
|
}
|
9
9
|
|
10
10
|
it "dumps to sql with quoted values" do
|
@@ -12,14 +12,14 @@ describe "Foreign Key definition" do
|
|
12
12
|
end
|
13
13
|
|
14
14
|
it "dumps to sql with deferrable values" do
|
15
|
-
options = {:name => "posts_user_fkey", :
|
16
|
-
deferred_definition =
|
15
|
+
options = {:name => "posts_user_fkey", :column => :user, :primary_key => :id, :deferrable => true}
|
16
|
+
deferred_definition = ::ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new(:posts, :users, options)
|
17
17
|
expect(deferred_definition.to_sql).to eq(%Q{CONSTRAINT posts_user_fkey FOREIGN KEY (#{quote_column_name('user')}) REFERENCES #{quote_table_name('users')} (#{quote_column_name('id')}) DEFERRABLE})
|
18
18
|
end
|
19
19
|
|
20
20
|
it "dumps to sql with initially deferrable values" do
|
21
|
-
options = {:name => "posts_user_fkey", :
|
22
|
-
initially_deferred_definition =
|
21
|
+
options = {:name => "posts_user_fkey", :column => :user, :primary_key => :id, :deferrable => :initially_deferred}
|
22
|
+
initially_deferred_definition = ::ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new(:posts, :users, options)
|
23
23
|
expect(initially_deferred_definition.to_sql).to eq(%Q{CONSTRAINT posts_user_fkey FOREIGN KEY (#{quote_column_name('user')}) REFERENCES #{quote_table_name('users')} (#{quote_column_name('id')}) DEFERRABLE INITIALLY DEFERRED})
|
24
24
|
end
|
25
25
|
|
data/spec/foreign_key_spec.rb
CHANGED
@@ -12,7 +12,7 @@ describe "Foreign Key" do
|
|
12
12
|
end
|
13
13
|
create_table :comments, :force => true do |t|
|
14
14
|
t.integer :user_id
|
15
|
-
t.foreign_key :user_id, :users
|
15
|
+
t.foreign_key :user_id, :users
|
16
16
|
end
|
17
17
|
end
|
18
18
|
class User < ::ActiveRecord::Base ; end
|
@@ -20,42 +20,40 @@ describe "Foreign Key" do
|
|
20
20
|
end
|
21
21
|
|
22
22
|
it "should report foreign key constraints" do
|
23
|
-
expect(Comment.foreign_keys.collect(&:
|
23
|
+
expect(Comment.foreign_keys.collect(&:column).flatten).to eq([ "user_id" ])
|
24
24
|
end
|
25
25
|
|
26
26
|
it "should report reverse foreign key constraints" do
|
27
|
-
expect(User.reverse_foreign_keys.collect(&:
|
27
|
+
expect(User.reverse_foreign_keys.collect(&:column).flatten).to eq([ "user_id" ])
|
28
28
|
end
|
29
29
|
|
30
30
|
end
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
end
|
32
|
+
context "with modifications to SQL generated by upstream visit_TableDefinition" do
|
33
|
+
before(:each) do
|
34
|
+
allow_any_instance_of(ActiveRecord::Base.connection.class.const_get(:SchemaCreation))
|
35
|
+
.to receive(:visit_TableDefinition_without_schema_plus)
|
36
|
+
.and_return('this is unexpected')
|
37
|
+
end
|
39
38
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
end
|
46
|
-
create_table :comments, :force => true do |t|
|
47
|
-
t.integer :user_id
|
48
|
-
t.foreign_key :user_id, :users, :id
|
49
|
-
end
|
39
|
+
it "raises an exception when attempting to create a table" do
|
40
|
+
expect {
|
41
|
+
define_schema(:auto_create => true) do
|
42
|
+
create_table :users, :force => true do |t|
|
43
|
+
t.string :login
|
50
44
|
end
|
51
|
-
|
52
|
-
|
45
|
+
create_table :comments, :force => true do |t|
|
46
|
+
t.integer :user_id
|
47
|
+
t.foreign_key :user_id, :users
|
48
|
+
end
|
49
|
+
end
|
50
|
+
}.to raise_error(RuntimeError, /Internal Error: Can't find.*Rails internals have changed/)
|
53
51
|
end
|
54
52
|
end
|
55
53
|
|
56
54
|
context "modification" do
|
57
55
|
|
58
|
-
before(:
|
56
|
+
before(:each) do
|
59
57
|
define_schema(:auto_create => false) do
|
60
58
|
create_table :users, :force => true do |t|
|
61
59
|
t.string :login
|
@@ -71,12 +69,13 @@ describe "Foreign Key" do
|
|
71
69
|
create_table :comments, :force => true do |t|
|
72
70
|
t.text :body
|
73
71
|
t.integer :post_id
|
74
|
-
t.foreign_key :post_id, :posts
|
72
|
+
t.foreign_key :post_id, :posts
|
75
73
|
end
|
76
74
|
end
|
77
75
|
class User < ::ActiveRecord::Base ; end
|
78
76
|
class Post < ::ActiveRecord::Base ; end
|
79
77
|
class Comment < ::ActiveRecord::Base ; end
|
78
|
+
Comment.reset_column_information
|
80
79
|
end
|
81
80
|
|
82
81
|
|
@@ -85,12 +84,7 @@ describe "Foreign Key" do
|
|
85
84
|
context "when is added", "posts(author_id)" do
|
86
85
|
|
87
86
|
before(:each) do
|
88
|
-
add_foreign_key(:posts, :
|
89
|
-
end
|
90
|
-
|
91
|
-
after(:each) do
|
92
|
-
fk = Post.foreign_keys.detect(&its.column_names == %w[author_id])
|
93
|
-
remove_foreign_key(:posts, fk.name)
|
87
|
+
add_foreign_key(:posts, :users, :column => :author_id, :on_update => :cascade, :on_delete => :restrict)
|
94
88
|
end
|
95
89
|
|
96
90
|
it "references users(id)" do
|
@@ -106,25 +100,21 @@ describe "Foreign Key" do
|
|
106
100
|
end
|
107
101
|
|
108
102
|
it "is available in Post.foreign_keys" do
|
109
|
-
expect(Post.foreign_keys.collect(&:
|
103
|
+
expect(Post.foreign_keys.collect(&:column)).to include('author_id')
|
110
104
|
end
|
111
105
|
|
112
106
|
it "is available in User.reverse_foreign_keys" do
|
113
|
-
expect(User.reverse_foreign_keys.collect(&:
|
107
|
+
expect(User.reverse_foreign_keys.collect(&:column)).to include('author_id')
|
114
108
|
end
|
115
109
|
|
116
110
|
end
|
117
111
|
|
118
112
|
context "when is dropped", "comments(post_id)" do
|
119
113
|
|
120
|
-
let(:foreign_key_name) { fk = Comment.foreign_keys.detect(&its.
|
114
|
+
let(:foreign_key_name) { fk = Comment.foreign_keys.detect(&its.column == 'post_id') and fk.name }
|
121
115
|
|
122
116
|
before(:each) do
|
123
|
-
remove_foreign_key(:comments, foreign_key_name)
|
124
|
-
end
|
125
|
-
|
126
|
-
after(:each) do
|
127
|
-
add_foreign_key(:comments, :post_id, :posts, :id)
|
117
|
+
remove_foreign_key(:comments, name: foreign_key_name)
|
128
118
|
end
|
129
119
|
|
130
120
|
it "doesn't reference posts(id)" do
|
@@ -132,22 +122,47 @@ describe "Foreign Key" do
|
|
132
122
|
end
|
133
123
|
|
134
124
|
it "is no longer available in Post.foreign_keys" do
|
135
|
-
expect(Comment.foreign_keys.collect(&:
|
125
|
+
expect(Comment.foreign_keys.collect(&:column)).not_to include('post_id')
|
136
126
|
end
|
137
127
|
|
138
128
|
it "is no longer available in User.reverse_foreign_keys" do
|
139
|
-
expect(Post.reverse_foreign_keys.collect(&:
|
129
|
+
expect(Post.reverse_foreign_keys.collect(&:column)).not_to include('post_id')
|
140
130
|
end
|
141
131
|
|
142
132
|
end
|
143
133
|
|
134
|
+
context "when drop using hash", "comments(post_id)" do
|
135
|
+
|
136
|
+
let(:foreign_key_name) { fk = Comment.foreign_keys.detect(&its.column == 'post_id') and fk.name }
|
137
|
+
|
138
|
+
it "finds by name" do
|
139
|
+
remove_foreign_key(:comments, name: foreign_key_name)
|
140
|
+
expect(Comment).not_to reference(:posts).on(:post_id)
|
141
|
+
end
|
142
|
+
|
143
|
+
it "finds by column_names" do
|
144
|
+
remove_foreign_key(:comments, column: "post_id", to_table: "posts")
|
145
|
+
expect(Comment).not_to reference(:posts).on(:post_id)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
context "when attempt to drop nonexistent foreign key" do
|
150
|
+
it "raises error" do
|
151
|
+
expect{remove_foreign_key(:comments, "posts", column: "nonesuch")}.to raise_error(/no foreign key/i)
|
152
|
+
end
|
153
|
+
|
154
|
+
it "does not error with :if_exists" do
|
155
|
+
expect{remove_foreign_key(:comments, "posts", column: "nonesuch", :if_exists => true)}.to_not raise_error
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
144
159
|
context "when referencing column and column is removed" do
|
145
160
|
|
146
|
-
let(:foreign_key_name) { Comment.foreign_keys.detect { |definition| definition.
|
161
|
+
let(:foreign_key_name) { Comment.foreign_keys.detect { |definition| definition.column == 'post_id' }.name }
|
147
162
|
|
148
163
|
it "should remove foreign keys" do
|
149
|
-
remove_foreign_key(:comments, foreign_key_name)
|
150
|
-
expect(Post.reverse_foreign_keys.collect { |fk| fk.
|
164
|
+
remove_foreign_key(:comments, name: foreign_key_name)
|
165
|
+
expect(Post.reverse_foreign_keys.collect { |fk| fk.column == 'post_id' && fk.from_table == "comments" }).to be_empty
|
151
166
|
end
|
152
167
|
|
153
168
|
end
|
@@ -164,9 +179,9 @@ describe "Foreign Key" do
|
|
164
179
|
it "can add, detect, and remove a foreign key without error" do
|
165
180
|
migration.suppress_messages do
|
166
181
|
expect {
|
167
|
-
migration.add_foreign_key(:references, :
|
168
|
-
foreign_key = migration.foreign_keys(:references).detect{|definition| definition.
|
169
|
-
migration.remove_foreign_key(:references, foreign_key.name)
|
182
|
+
migration.add_foreign_key(:references, :posts)
|
183
|
+
foreign_key = migration.foreign_keys(:references).detect{|definition| definition.column == "post_id"}
|
184
|
+
migration.remove_foreign_key(:references, name: foreign_key.name)
|
170
185
|
}.to_not raise_error
|
171
186
|
end
|
172
187
|
end
|
@@ -178,13 +193,13 @@ describe "Foreign Key" do
|
|
178
193
|
|
179
194
|
it "when attempting to add" do
|
180
195
|
expect {
|
181
|
-
add_foreign_key(:posts, :
|
196
|
+
add_foreign_key(:posts, :users, :column => :author_id, :on_update => :cascade, :on_delete => :restrict)
|
182
197
|
}.to raise_error(NotImplementedError)
|
183
198
|
end
|
184
199
|
|
185
200
|
it "when attempting to remove" do
|
186
201
|
expect {
|
187
|
-
remove_foreign_key(:posts, "dummy")
|
202
|
+
remove_foreign_key(:posts, name: "dummy")
|
188
203
|
}.to raise_error(NotImplementedError)
|
189
204
|
end
|
190
205
|
|
data/spec/migration_spec.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
require
|
2
|
+
require 'spec_helper'
|
3
3
|
|
4
4
|
describe ActiveRecord::Migration do
|
5
5
|
|
@@ -18,7 +18,7 @@ describe ActiveRecord::Migration do
|
|
18
18
|
t.string :content
|
19
19
|
t.integer :user
|
20
20
|
t.integer :user_id
|
21
|
-
t.foreign_key :user_id, :users, :id
|
21
|
+
t.foreign_key :user_id, :users, :primary_key => :id
|
22
22
|
end
|
23
23
|
|
24
24
|
create_table :posts, :force => true do |t|
|
@@ -172,27 +172,6 @@ describe ActiveRecord::Migration do
|
|
172
172
|
expect(@model).to reference(@model.table_name, :id).on(:parent_id)
|
173
173
|
end
|
174
174
|
|
175
|
-
it "should create an index if specified on column" do
|
176
|
-
recreate_table(@model) do |t|
|
177
|
-
t.integer :state, :index => true
|
178
|
-
end
|
179
|
-
expect(@model).to have_index.on(:state)
|
180
|
-
end
|
181
|
-
|
182
|
-
it "should create a unique index if specified on column" do
|
183
|
-
recreate_table(@model) do |t|
|
184
|
-
t.integer :state, :index => { :unique => true }
|
185
|
-
end
|
186
|
-
expect(@model).to have_unique_index.on(:state)
|
187
|
-
end
|
188
|
-
|
189
|
-
it "should create a unique index if specified on column using shorthand" do
|
190
|
-
recreate_table(@model) do |t|
|
191
|
-
t.integer :state, :index => :unique
|
192
|
-
end
|
193
|
-
expect(@model).to have_unique_index.on(:state)
|
194
|
-
end
|
195
|
-
|
196
175
|
[:references, :belongs_to].each do |reftype|
|
197
176
|
|
198
177
|
context "when define #{reftype}" do
|
@@ -229,7 +208,7 @@ describe ActiveRecord::Migration do
|
|
229
208
|
it "should create a two-column index if polymophic and index requested" do
|
230
209
|
create_reference(reftype, :post, :polymorphic => true, :index => true)
|
231
210
|
expect(@model).to have_index.on([:post_id, :post_type])
|
232
|
-
end
|
211
|
+
end
|
233
212
|
|
234
213
|
protected
|
235
214
|
|
@@ -242,49 +221,6 @@ describe ActiveRecord::Migration do
|
|
242
221
|
end
|
243
222
|
end
|
244
223
|
|
245
|
-
it "should pass index length option properly", :mysql => :only do
|
246
|
-
recreate_table(@model) do |t|
|
247
|
-
t.string :foo
|
248
|
-
t.string :bar, :index => { :with => :foo, :length => { :foo => 8, :bar => 12 }}
|
249
|
-
end
|
250
|
-
index = @model.indexes.first
|
251
|
-
expect(Hash[index.columns.zip(index.lengths.map(&:to_i))]).to eq({ "foo" => 8, "bar" => 12})
|
252
|
-
end
|
253
|
-
|
254
|
-
it "should create an index if specified explicitly" do
|
255
|
-
recreate_table(@model) do |t|
|
256
|
-
t.integer :state
|
257
|
-
t.index :state
|
258
|
-
end
|
259
|
-
expect(@model).to have_index.on(:state)
|
260
|
-
end
|
261
|
-
|
262
|
-
it "should create a unique index if specified explicitly" do
|
263
|
-
recreate_table(@model) do |t|
|
264
|
-
t.integer :state
|
265
|
-
t.index :state, :unique => true
|
266
|
-
end
|
267
|
-
expect(@model).to have_unique_index.on(:state)
|
268
|
-
end
|
269
|
-
|
270
|
-
it "should create a multiple-column index if specified" do
|
271
|
-
recreate_table(@model) do |t|
|
272
|
-
t.integer :city
|
273
|
-
t.integer :state, :index => { :with => :city }
|
274
|
-
end
|
275
|
-
expect(@model).to have_index.on([:state, :city])
|
276
|
-
end
|
277
|
-
|
278
|
-
it "should create the index without modifying the input hash" do
|
279
|
-
hash = { :with => :foo, :length => { :foo => 8, :bar => 12 }}
|
280
|
-
hash_original = hash.dup
|
281
|
-
recreate_table(@model) do |t|
|
282
|
-
t.string :foo
|
283
|
-
t.string :bar, :index => hash
|
284
|
-
end
|
285
|
-
expect(hash).to eq(hash_original)
|
286
|
-
end
|
287
|
-
|
288
224
|
it "should auto-index foreign keys only" do
|
289
225
|
recreate_table(@model) do |t|
|
290
226
|
t.integer :user_id
|
@@ -323,7 +259,7 @@ describe ActiveRecord::Migration do
|
|
323
259
|
end
|
324
260
|
end
|
325
261
|
|
326
|
-
actions = [:cascade, :restrict, :
|
262
|
+
actions = [:cascade, :restrict, :nullify, :set_default, :no_action]
|
327
263
|
|
328
264
|
actions.each do |action|
|
329
265
|
if action == :set_default
|
@@ -419,18 +355,18 @@ describe ActiveRecord::Migration do
|
|
419
355
|
it "should override on_update action per column" do
|
420
356
|
with_fk_config(:on_update => :cascade) do
|
421
357
|
recreate_table @model, :foreign_keys => {:on_update => :restrict} do |t|
|
422
|
-
t.integer :user_id, :foreign_key => { :on_update => :
|
358
|
+
t.integer :user_id, :foreign_key => { :on_update => :nullify }
|
423
359
|
end
|
424
|
-
expect(@model).to reference.on(:user_id).on_update(:
|
360
|
+
expect(@model).to reference.on(:user_id).on_update(:nullify)
|
425
361
|
end
|
426
362
|
end
|
427
363
|
|
428
364
|
it "should override on_delete action per column" do
|
429
365
|
with_fk_config(:on_delete => :cascade) do
|
430
366
|
recreate_table @model, :foreign_keys => {:on_delete => :restrict} do |t|
|
431
|
-
t.integer :user_id, :foreign_key => { :on_delete => :
|
367
|
+
t.integer :user_id, :foreign_key => { :on_delete => :nullify }
|
432
368
|
end
|
433
|
-
expect(@model).to reference.on(:user_id).on_delete(:
|
369
|
+
expect(@model).to reference.on(:user_id).on_delete(:nullify)
|
434
370
|
end
|
435
371
|
end
|
436
372
|
|
@@ -477,13 +413,6 @@ describe ActiveRecord::Migration do
|
|
477
413
|
[false, true].each do |bulk|
|
478
414
|
suffix = bulk ? ' with :bulk option' : ""
|
479
415
|
|
480
|
-
it "should create an index if specified on column"+suffix do
|
481
|
-
change_table(@model, :bulk => bulk) do |t|
|
482
|
-
t.integer :state, :index => true
|
483
|
-
end
|
484
|
-
expect(@model).to have_index.on(:state)
|
485
|
-
end
|
486
|
-
|
487
416
|
it "should create a foreign key constraint"+suffix, :sqlite3 => :skip do
|
488
417
|
change_table(@model, :bulk => bulk) do |t|
|
489
418
|
t.integer :user_id
|
@@ -508,7 +437,7 @@ describe ActiveRecord::Migration do
|
|
508
437
|
Comment.reset_column_information
|
509
438
|
expect(Comment).not_to reference(:users, :id).on(:user_id)
|
510
439
|
end
|
511
|
-
end
|
440
|
+
end
|
512
441
|
|
513
442
|
it "should create a foreign key constraint using :references"+suffix, :sqlite3 => :skip do
|
514
443
|
change_table(@model, :bulk => bulk) do |t|
|
@@ -542,12 +471,6 @@ describe ActiveRecord::Migration do
|
|
542
471
|
@model = Comment
|
543
472
|
end
|
544
473
|
|
545
|
-
it "should create an index" do
|
546
|
-
add_column(:slug, :string, :index => true) do
|
547
|
-
expect(@model).to have_index.on(:slug)
|
548
|
-
end
|
549
|
-
end
|
550
|
-
|
551
474
|
it "should create foreign key" do
|
552
475
|
add_column(:post_id, :integer) do
|
553
476
|
expect(@model).to reference(:posts, :id).on(:post_id)
|
@@ -596,31 +519,6 @@ describe ActiveRecord::Migration do
|
|
596
519
|
end
|
597
520
|
end
|
598
521
|
|
599
|
-
it "should create an index if specified" do
|
600
|
-
add_column(:post_id, :integer, :index => true) do
|
601
|
-
expect(@model).to have_index.on(:post_id)
|
602
|
-
end
|
603
|
-
end
|
604
|
-
|
605
|
-
it "should create a unique index if specified" do
|
606
|
-
add_column(:post_id, :integer, :index => { :unique => true }) do
|
607
|
-
expect(@model).to have_unique_index.on(:post_id)
|
608
|
-
end
|
609
|
-
end
|
610
|
-
|
611
|
-
it "should create a unique index if specified by shorthand" do
|
612
|
-
add_column(:post_id, :integer, :index => :unique) do
|
613
|
-
expect(@model).to have_unique_index.on(:post_id)
|
614
|
-
end
|
615
|
-
end
|
616
|
-
|
617
|
-
it "should allow custom name for index" do
|
618
|
-
index_name = 'comments_post_id_unique_index'
|
619
|
-
add_column(:post_id, :integer, :index => { :unique => true, :name => index_name }) do
|
620
|
-
expect(@model).to have_unique_index(:name => index_name).on(:post_id)
|
621
|
-
end
|
622
|
-
end
|
623
|
-
|
624
522
|
it "should auto-index if specified in global options" do
|
625
523
|
SchemaPlus.config.foreign_keys.auto_index = true
|
626
524
|
add_column(:post_id, :integer) do
|
@@ -665,8 +563,8 @@ describe ActiveRecord::Migration do
|
|
665
563
|
it "should allow to overwrite default actions" do
|
666
564
|
SchemaPlus.config.foreign_keys.on_delete = :cascade
|
667
565
|
SchemaPlus.config.foreign_keys.on_update = :restrict
|
668
|
-
add_column(:post_id, :integer, :foreign_key => { :on_update => :
|
669
|
-
expect(@model).to reference.on(:post_id).on_delete(:
|
566
|
+
add_column(:post_id, :integer, :foreign_key => { :on_update => :nullify, :on_delete => :nullify}) do
|
567
|
+
expect(@model).to reference.on(:post_id).on_delete(:nullify).on_update(:nullify)
|
670
568
|
end
|
671
569
|
SchemaPlus.config.foreign_keys.on_delete = nil
|
672
570
|
end
|
@@ -685,96 +583,78 @@ describe ActiveRecord::Migration do
|
|
685
583
|
end
|
686
584
|
|
687
585
|
|
688
|
-
context "when
|
586
|
+
context "when column is changed", :sqlite3 => :skip do
|
689
587
|
|
690
588
|
before(:each) do
|
691
589
|
@model = Comment
|
692
590
|
end
|
693
591
|
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
expect(@model).to reference(:users, :login).on(:user)
|
699
|
-
end
|
592
|
+
it "should create foreign key" do
|
593
|
+
change_column :user, :string, :foreign_key => { :references => [:users, :login] }
|
594
|
+
expect(@model).to reference(:users, :login).on(:user)
|
595
|
+
end
|
700
596
|
|
701
|
-
|
597
|
+
context "and initially references to users table" do
|
702
598
|
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
end
|
599
|
+
before(:each) do
|
600
|
+
recreate_table @model do |t|
|
601
|
+
t.integer :user_id
|
707
602
|
end
|
603
|
+
end
|
708
604
|
|
709
|
-
|
710
|
-
|
711
|
-
|
605
|
+
it "should have foreign key" do
|
606
|
+
expect(@model).to reference(:users)
|
607
|
+
end
|
712
608
|
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
609
|
+
it "should drop foreign key if it is no longer valid" do
|
610
|
+
change_column :user_id, :integer, :foreign_key => { :references => :members }
|
611
|
+
expect(@model).not_to reference(:users)
|
612
|
+
end
|
717
613
|
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
614
|
+
it "should drop foreign key if requested to do so" do
|
615
|
+
change_column :user_id, :integer, :foreign_key => { :references => nil }
|
616
|
+
expect(@model).not_to reference(:users)
|
617
|
+
end
|
722
618
|
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
619
|
+
it "should remove auto-created index if foreign key is removed" do
|
620
|
+
expect(@model).to have_index.on(:user_id) # sanity check that index was auto-created
|
621
|
+
change_column :user_id, :integer, :foreign_key => { :references => nil }
|
622
|
+
expect(@model).not_to have_index.on(:user_id)
|
623
|
+
end
|
728
624
|
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
625
|
+
it "should reference pointed table afterwards if new one is created" do
|
626
|
+
change_column :user_id, :integer, :foreign_key => { :references => :members }
|
627
|
+
expect(@model).to reference(:members)
|
628
|
+
end
|
733
629
|
|
734
|
-
|
630
|
+
it "should maintain foreign key if it's unaffected by change" do
|
631
|
+
change_column :user_id, :integer, :default => 0
|
632
|
+
expect(@model).to reference(:users)
|
633
|
+
end
|
634
|
+
|
635
|
+
it "should maintain foreign key if it's unaffected by change, even if auto_index is off" do
|
636
|
+
with_fk_config(:auto_create => false) do
|
735
637
|
change_column :user_id, :integer, :default => 0
|
736
638
|
expect(@model).to reference(:users)
|
737
639
|
end
|
738
|
-
|
739
|
-
it "should maintain foreign key if it's unaffected by change, even if auto_index is off" do
|
740
|
-
with_fk_config(:auto_create => false) do
|
741
|
-
change_column :user_id, :integer, :default => 0
|
742
|
-
expect(@model).to reference(:users)
|
743
|
-
end
|
744
|
-
end
|
745
|
-
|
746
640
|
end
|
747
641
|
|
748
|
-
context "if column defined without foreign key but with index" do
|
749
|
-
before(:each) do
|
750
|
-
recreate_table @model do |t|
|
751
|
-
t.integer :user_id, :foreign_key => false, :index => true
|
752
|
-
end
|
753
|
-
end
|
754
|
-
|
755
|
-
it "should create the index" do
|
756
|
-
expect(@model).to have_index.on(:user_id)
|
757
|
-
end
|
758
|
-
|
759
|
-
it "adding foreign key should not fail due to attempt to auto-create existing index" do
|
760
|
-
expect { change_column :user_id, :integer, :foreign_key => true }.to_not raise_error
|
761
|
-
end
|
762
|
-
end
|
763
642
|
end
|
764
643
|
|
765
|
-
context "without foreign
|
766
|
-
|
767
|
-
it "doesn't auto-add foreign keys" do
|
644
|
+
context "if column defined without foreign key but with index" do
|
645
|
+
before(:each) do
|
768
646
|
recreate_table @model do |t|
|
769
|
-
t.integer :user_id, :foreign_key => false
|
770
|
-
t.string :other_column
|
771
|
-
end
|
772
|
-
with_fk_auto_create do
|
773
|
-
change_column :other_column, :text
|
647
|
+
t.integer :user_id, :foreign_key => false, :index => true
|
774
648
|
end
|
775
|
-
expect(@model).to_not reference(:users)
|
776
649
|
end
|
777
650
|
|
651
|
+
it "should create the index" do
|
652
|
+
expect(@model).to have_index.on(:user_id)
|
653
|
+
end
|
654
|
+
|
655
|
+
it "adding foreign key should not fail due to attempt to auto-create existing index" do
|
656
|
+
expect { change_column :user_id, :integer, :foreign_key => true }.to_not raise_error
|
657
|
+
end
|
778
658
|
end
|
779
659
|
|
780
660
|
protected
|
@@ -788,7 +668,6 @@ describe ActiveRecord::Migration do
|
|
788
668
|
|
789
669
|
end
|
790
670
|
|
791
|
-
|
792
671
|
context "when column is removed", :sqlite3 => :skip do
|
793
672
|
before(:each) do
|
794
673
|
@model = Comment
|
@@ -833,21 +712,6 @@ describe ActiveRecord::Migration do
|
|
833
712
|
end
|
834
713
|
end
|
835
714
|
|
836
|
-
around(:each) do |example|
|
837
|
-
begin
|
838
|
-
example.run
|
839
|
-
ensure
|
840
|
-
ActiveRecord::Migration.suppress_messages do
|
841
|
-
ActiveRecord::Migration.rename_table :newname, :comments
|
842
|
-
end
|
843
|
-
end
|
844
|
-
end
|
845
|
-
|
846
|
-
it "should rename rails-named indexes" do
|
847
|
-
index = ActiveRecord::Base.connection.indexes(:newname).find(&its.columns == ['xyz'])
|
848
|
-
expect(index.name).to match(/^index_newname_on/)
|
849
|
-
end
|
850
|
-
|
851
715
|
it "should rename fk indexes" do
|
852
716
|
index = ActiveRecord::Base.connection.indexes(:newname).find(&its.columns == ['user_id'])
|
853
717
|
expect(index.name).to match(/^fk__newname_/)
|
@@ -873,15 +737,6 @@ describe ActiveRecord::Migration do
|
|
873
737
|
end
|
874
738
|
end
|
875
739
|
|
876
|
-
around(:each) do |example|
|
877
|
-
begin
|
878
|
-
example.run
|
879
|
-
ensure
|
880
|
-
ActiveRecord::Migration.suppress_messages do
|
881
|
-
ActiveRecord::Migration.rename_table :newname, :comments
|
882
|
-
end
|
883
|
-
end
|
884
|
-
end
|
885
740
|
it "should rename foreign key constraints" do
|
886
741
|
names = ActiveRecord::Base.connection.foreign_keys(:newname).map(&:name)
|
887
742
|
expect(names.grep(/newname/)).to eq(names)
|