sparkfly-foreigner 0.5.4
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.
- data/.gitignore +3 -0
- data/MIT-LICENSE +21 -0
- data/README.textile +105 -0
- data/Rakefile +38 -0
- data/VERSION +1 -0
- data/lib/foreigner.rb +58 -0
- data/lib/foreigner/connection_adapters/abstract/schema_definitions.rb +154 -0
- data/lib/foreigner/connection_adapters/abstract/schema_statements.rb +75 -0
- data/lib/foreigner/connection_adapters/mysql_adapter.rb +48 -0
- data/lib/foreigner/connection_adapters/postgresql_adapter.rb +47 -0
- data/lib/foreigner/connection_adapters/sqlite3_adapter.rb +46 -0
- data/lib/foreigner/schema_dumper.rb +47 -0
- data/lib/foreigner/semantics/sql_2003.rb +78 -0
- data/spec/adapter_helper.rb +100 -0
- data/spec/factory_helper.rb +70 -0
- data/spec/mysql/schema_extractor_spec.rb +143 -0
- data/spec/mysql/schema_spec.rb +87 -0
- data/spec/mysql/semantics_spec.rb +75 -0
- data/spec/postgresql/schema_extractor_spec.rb +143 -0
- data/spec/postgresql/schema_spec.rb +152 -0
- data/spec/postgresql/semantics_spec.rb +75 -0
- data/spec/schema_dumper_spec.rb +96 -0
- data/spec/spec_helper.rb +48 -0
- data/spec/sqlite3/schema_spec.rb +86 -0
- data/tasks/foreigner_tasks.rake +4 -0
- metadata +96 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
require File.expand_path('../spec_helper.rb', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe Foreigner::ConnectionAdapters::MysqlAdapter do
|
4
|
+
include MigrationFactory
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
@adapter = AdapterHelper::MySQLTestAdapter.new
|
8
|
+
@adapter.recreate_test_environment
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'when creating tables with t.foreign_key' do
|
12
|
+
|
13
|
+
it 'should understand t.foreign_key' do
|
14
|
+
create_table :items do |t|
|
15
|
+
t.string :name
|
16
|
+
t.references :collection, :null => false
|
17
|
+
t.foreign_key :collection
|
18
|
+
end
|
19
|
+
|
20
|
+
@adapter.schema(:items).should match(/FOREIGN KEY\s*\(\`collection_id\`\) REFERENCES \`collections\`\s*\(\`id\`\)/)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should accept a :column parameter' do
|
24
|
+
@column = :item_collection_id
|
25
|
+
|
26
|
+
create_table :items do |t|
|
27
|
+
t.string :name
|
28
|
+
t.integer @column
|
29
|
+
t.foreign_key :collection, :column => @column
|
30
|
+
end
|
31
|
+
|
32
|
+
@adapter.schema(:items).should match(/FOREIGN KEY\s*\(\`#{@column}\`\) REFERENCES \`collections\`\s*\(\`id\`\)/)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should accept :dependent => :nullify' do
|
36
|
+
create_table :items do |t|
|
37
|
+
t.string :name
|
38
|
+
t.references :collection
|
39
|
+
t.foreign_key :collection, :dependent => :nullify
|
40
|
+
end
|
41
|
+
|
42
|
+
@adapter.schema(:items).should match(/FOREIGN KEY\s*\(\`collection_id\`\) REFERENCES \`collections\`\s*\(\`id\`\) ON DELETE SET NULL/)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should accept :dependent => :delete' do
|
46
|
+
create_table :items do |t|
|
47
|
+
t.string :name
|
48
|
+
t.references :collection
|
49
|
+
t.foreign_key :collection, :dependent => :delete
|
50
|
+
end
|
51
|
+
|
52
|
+
@adapter.schema(:items).should match(/FOREIGN KEY\s*\(\`collection_id\`\) REFERENCES \`collections\`\s*\(\`id\`\) ON DELETE CASCADE/)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe 'when creating tables with t.reference' do
|
57
|
+
|
58
|
+
it 'should accept a t.references constraint' do
|
59
|
+
create_table :items do |t|
|
60
|
+
t.string :name
|
61
|
+
t.references :collection, :foreign_key => true
|
62
|
+
end
|
63
|
+
|
64
|
+
@adapter.schema(:items).should match(/FOREIGN KEY\s*\(\`collection_id\`\) REFERENCES \`collections\`\s*\(\`id\`\)/)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should accept :foreign_key => { :dependent => :nullify }' do
|
68
|
+
create_table :items do |t|
|
69
|
+
t.string :name
|
70
|
+
t.references :collection, :foreign_key => {:dependent => :nullify}
|
71
|
+
end
|
72
|
+
|
73
|
+
@adapter.schema(:items).match(/FOREIGN KEY\s*\(\`collection_id\`\) REFERENCES \`collections\`\s*\(\`id\`\) ON DELETE SET NULL/)
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should accept :foreign_key => { :dependent => :delete }' do
|
77
|
+
create_table :items do |t|
|
78
|
+
t.string :name
|
79
|
+
t.references :collection, :foreign_key => {:dependent => :delete}
|
80
|
+
end
|
81
|
+
|
82
|
+
@adapter.schema(:items).should match(/FOREIGN KEY\s*\(\`collection_id\`\) REFERENCES \`collections\`\s*\(\`id\`\) ON DELETE CASCADE/)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require File.expand_path('../spec_helper.rb', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe Foreigner::ConnectionAdapters::MysqlAdapter do
|
4
|
+
include MigrationFactory
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
@adapter = AdapterHelper::MySQLTestAdapter.new
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'when adding foreign keys' do
|
11
|
+
it 'should add foreign key without options' do
|
12
|
+
@adapter.add_foreign_key(:employees, :companies).should eql(
|
13
|
+
"ALTER TABLE `employees` ADD CONSTRAINT `fk_employees_company_id` FOREIGN KEY (`company_id`) REFERENCES `companies`(id)"
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should add foreign key with a name' do
|
18
|
+
@name = 'favorite_company_fk'
|
19
|
+
@adapter.add_foreign_key(:employees, :companies, :name => @name).should eql(
|
20
|
+
"ALTER TABLE `employees` ADD CONSTRAINT `#{@name}` FOREIGN KEY (`company_id`) REFERENCES `companies`(id)"
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should add foreign key with a column' do
|
25
|
+
@column = 'last_employer_id'
|
26
|
+
@adapter.add_foreign_key(:employees, :companies, :column => @column).should eql(
|
27
|
+
"ALTER TABLE `employees` ADD CONSTRAINT `fk_employees_last_employer_id` FOREIGN KEY (`#{@column}`) REFERENCES `companies`(id)"
|
28
|
+
)
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should add foreign key with column and a name' do
|
33
|
+
@name = 'favorite_company_fk'
|
34
|
+
@column = 'last_employer_id'
|
35
|
+
@adapter.add_foreign_key(:employees, :companies, :column => @column, :name => @name).should eql(
|
36
|
+
"ALTER TABLE `employees` ADD CONSTRAINT `#{@name}` FOREIGN KEY (`#{@column}`) REFERENCES `companies`(id)"
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should add foreign key with :dependent => :delete' do
|
41
|
+
@adapter.add_foreign_key(:employees, :companies, :dependent => :delete).should eql(
|
42
|
+
"ALTER TABLE `employees` ADD CONSTRAINT `fk_employees_company_id` FOREIGN KEY (`company_id`) REFERENCES `companies`(id) " +
|
43
|
+
"ON DELETE CASCADE")
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should add foreign key with :dependent => :nullify' do
|
47
|
+
@adapter.add_foreign_key(:employees, :companies, :dependent => :nullify).should eql(
|
48
|
+
"ALTER TABLE `employees` ADD CONSTRAINT `fk_employees_company_id` FOREIGN KEY (`company_id`) REFERENCES `companies`(id) " +
|
49
|
+
"ON DELETE SET NULL"
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe 'when dropping foreign keys' do
|
55
|
+
it 'should drop foreign key' do
|
56
|
+
@adapter.remove_foreign_key(:suppliers, :companies).should eql(
|
57
|
+
"ALTER TABLE `suppliers` DROP FOREIGN KEY `fk_suppliers_company_id`"
|
58
|
+
)
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should drop foreign key by name' do
|
62
|
+
@adapter.remove_foreign_key(:suppliers, :name => "belongs_to_supplier").should eql(
|
63
|
+
"ALTER TABLE `suppliers` DROP FOREIGN KEY `belongs_to_supplier`"
|
64
|
+
)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should drop foreign key by column' do
|
68
|
+
@adapter.remove_foreign_key(:suppliers, :column => "ship_to_id").should eql(
|
69
|
+
"ALTER TABLE `suppliers` DROP FOREIGN KEY `fk_suppliers_ship_to_id`"
|
70
|
+
)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
@@ -0,0 +1,143 @@
|
|
1
|
+
require File.expand_path('../spec_helper.rb', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe Foreigner::ConnectionAdapters::PostgreSQLAdapter do
|
4
|
+
include MigrationFactory
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
@adapter = AdapterHelper::PostgreSQLTestAdapter.new
|
8
|
+
@adapter.recreate_test_environment
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'when extracting foreign keys from a table' do
|
12
|
+
it 'should extract single foreign key' do
|
13
|
+
create_table :items do |t|
|
14
|
+
t.string :name
|
15
|
+
t.references :collection, :null => false
|
16
|
+
t.foreign_key :collection
|
17
|
+
end
|
18
|
+
|
19
|
+
@adapter.foreign_keys(:items).length.should eql(1)
|
20
|
+
foreign_key = @adapter.foreign_keys(:items)[0]
|
21
|
+
|
22
|
+
# Duck Typing
|
23
|
+
foreign_key.should be_respond_to(:from_table)
|
24
|
+
foreign_key.should be_respond_to(:to_table)
|
25
|
+
foreign_key.should be_respond_to(:options)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should extract multiple foreign keys' do
|
29
|
+
create_table :owners do |t|
|
30
|
+
t.string :name
|
31
|
+
end
|
32
|
+
|
33
|
+
create_table :items do |t|
|
34
|
+
t.string :name
|
35
|
+
t.references :collection, :null => false
|
36
|
+
t.foreign_key :collection
|
37
|
+
t.references :owner, :null => false
|
38
|
+
t.foreign_key :owner
|
39
|
+
end
|
40
|
+
|
41
|
+
@adapter.foreign_keys(:items).length.should eql(2)
|
42
|
+
foreign_key_names = @adapter.foreign_keys(:items).map(&:to_table)
|
43
|
+
foreign_key_names.should be_include('collections')
|
44
|
+
foreign_key_names.should be_include('owners')
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should extract referencing table' do
|
48
|
+
create_table :items do |t|
|
49
|
+
t.string :name
|
50
|
+
t.references :collection, :null => false
|
51
|
+
t.foreign_key :collection
|
52
|
+
end
|
53
|
+
|
54
|
+
@adapter.foreign_keys(:items).length.should eql(1)
|
55
|
+
foreign_key = @adapter.foreign_keys(:items)[0]
|
56
|
+
foreign_key.from_table.should eql('items')
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should extract foreign table' do
|
60
|
+
create_table :items do |t|
|
61
|
+
t.string :name
|
62
|
+
t.references :collection, :null => false
|
63
|
+
t.foreign_key :collection
|
64
|
+
end
|
65
|
+
|
66
|
+
@adapter.foreign_keys(:items).length.should eql(1)
|
67
|
+
foreign_key = @adapter.foreign_keys(:items)[0]
|
68
|
+
foreign_key.to_table.should eql('collections')
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should extract foreign key name' do
|
72
|
+
fk_name = 'custom_foreign_key'
|
73
|
+
|
74
|
+
create_migration do
|
75
|
+
create_table :items do |t|
|
76
|
+
t.string :name
|
77
|
+
t.references :collection, :null => false
|
78
|
+
end
|
79
|
+
add_foreign_key :items, :collections, :name => fk_name
|
80
|
+
end.up
|
81
|
+
|
82
|
+
@adapter.foreign_keys(:items).length.should eql(1)
|
83
|
+
foreign_key = @adapter.foreign_keys(:items)[0]
|
84
|
+
foreign_key.options[:name].should eql(fk_name)
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should extract foreign column' do
|
88
|
+
create_table :items do |t|
|
89
|
+
t.string :name
|
90
|
+
t.references :collection, :null => false
|
91
|
+
t.foreign_key :collection
|
92
|
+
end
|
93
|
+
|
94
|
+
@adapter.foreign_keys(:items).length.should eql(1)
|
95
|
+
foreign_key = @adapter.foreign_keys(:items)[0]
|
96
|
+
foreign_key.options[:column].should eql('collection_id')
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'should extract primary key' do
|
100
|
+
primary_key = 'acctno'
|
101
|
+
create_table :accounts, :primary_key => primary_key do |t|
|
102
|
+
t.integer primary_key, :null => false
|
103
|
+
t.string :name
|
104
|
+
end
|
105
|
+
|
106
|
+
create_migration do
|
107
|
+
create_table :items do |t|
|
108
|
+
t.string :name
|
109
|
+
t.integer primary_key, :null => false
|
110
|
+
end
|
111
|
+
add_foreign_key :items, :accounts, :column => primary_key, :primary_key => primary_key
|
112
|
+
end.up
|
113
|
+
|
114
|
+
@adapter.foreign_keys(:items).length.should eql(1)
|
115
|
+
foreign_key = @adapter.foreign_keys(:items)[0]
|
116
|
+
foreign_key.options[:primary_key].should eql(primary_key)
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'should extract :dependent => :nullify' do
|
120
|
+
@dependent = :nullify
|
121
|
+
create_table :items do |t|
|
122
|
+
t.string :name
|
123
|
+
t.references :collection, :foreign_key => {:dependent => @dependent}
|
124
|
+
end
|
125
|
+
|
126
|
+
foreign_key = @adapter.foreign_keys(:items)[0]
|
127
|
+
foreign_key.options[:dependent].should eql(@dependent)
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'should extract :dependent => :delete' do
|
131
|
+
@dependent = :delete
|
132
|
+
create_table :items do |t|
|
133
|
+
t.string :name
|
134
|
+
t.references :collection, :foreign_key => {:dependent => @dependent}
|
135
|
+
end
|
136
|
+
|
137
|
+
foreign_key = @adapter.foreign_keys(:items)[0]
|
138
|
+
foreign_key.options[:dependent].should eql(@dependent)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require File.expand_path('../spec_helper.rb', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe Foreigner::ConnectionAdapters::PostgreSQLAdapter do
|
4
|
+
include MigrationFactory
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
@adapter = AdapterHelper::PostgreSQLTestAdapter.new
|
8
|
+
@adapter.recreate_test_environment
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'when creating tables with t.foreign_key' do
|
12
|
+
|
13
|
+
it 'should understand t.foreign_key' do
|
14
|
+
create_table :items do |t|
|
15
|
+
t.string :name
|
16
|
+
t.references :collection, :null => false
|
17
|
+
t.foreign_key :collection
|
18
|
+
end
|
19
|
+
|
20
|
+
foreign_key = @adapter.foreign_keys(:items)[0]
|
21
|
+
foreign_key.to_table.should eql('collections')
|
22
|
+
foreign_key.options[:primary_key].should eql('id')
|
23
|
+
foreign_key.options[:column].should eql('collection_id')
|
24
|
+
foreign_key.options[:dependent].should be_nil
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should use a default foreign key name' do
|
28
|
+
create_table :items do |t|
|
29
|
+
t.string :name
|
30
|
+
t.references :collection, :null => false
|
31
|
+
t.foreign_key :collection
|
32
|
+
end
|
33
|
+
|
34
|
+
foreign_key = @adapter.foreign_keys(:items)[0]
|
35
|
+
foreign_key.options[:name].should_not be_nil
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should use a conventional primary key' do
|
39
|
+
create_table :items do |t|
|
40
|
+
t.string :name
|
41
|
+
t.references :collection, :null => false
|
42
|
+
t.foreign_key :collection
|
43
|
+
end
|
44
|
+
|
45
|
+
foreign_key = @adapter.foreign_keys(:items)[0]
|
46
|
+
foreign_key.options[:primary_key].should eql('id')
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should use a conventional column id' do
|
50
|
+
create_table :items do |t|
|
51
|
+
t.string :name
|
52
|
+
t.references :collection, :null => false
|
53
|
+
t.foreign_key :collection
|
54
|
+
end
|
55
|
+
|
56
|
+
foreign_key = @adapter.foreign_keys(:items)[0]
|
57
|
+
foreign_key.options[:column].should eql('collection_id')
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should accept a :column parameter' do
|
61
|
+
@column = :item_collection_id
|
62
|
+
|
63
|
+
create_table :items do |t|
|
64
|
+
t.string :name
|
65
|
+
t.integer @column
|
66
|
+
t.foreign_key :collection, :column => @column
|
67
|
+
end
|
68
|
+
|
69
|
+
foreign_key = @adapter.foreign_keys(:items)[0]
|
70
|
+
foreign_key.to_table.should eql('collections')
|
71
|
+
foreign_key.options[:primary_key].should eql('id')
|
72
|
+
foreign_key.options[:column].should eql(@column.to_s)
|
73
|
+
foreign_key.options[:dependent].should be_nil
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should accept :dependent => :nullify' do
|
77
|
+
@dependent = :nullify
|
78
|
+
create_table :items do |t|
|
79
|
+
t.string :name
|
80
|
+
t.references :collection
|
81
|
+
t.foreign_key :collection, :dependent => @dependent
|
82
|
+
end
|
83
|
+
|
84
|
+
foreign_key = @adapter.foreign_keys(:items)[0]
|
85
|
+
foreign_key.to_table.should eql('collections')
|
86
|
+
foreign_key.options[:primary_key].should eql('id')
|
87
|
+
foreign_key.options[:column].should eql('collection_id')
|
88
|
+
foreign_key.options[:dependent].should eql(@dependent)
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should accept :dependent => :delete' do
|
92
|
+
@dependent = :delete
|
93
|
+
create_table :items do |t|
|
94
|
+
t.string :name
|
95
|
+
t.references :collection
|
96
|
+
t.foreign_key :collection, :dependent => @dependent
|
97
|
+
end
|
98
|
+
|
99
|
+
foreign_key = @adapter.foreign_keys(:items)[0]
|
100
|
+
foreign_key.to_table.should eql('collections')
|
101
|
+
foreign_key.options[:primary_key].should eql('id')
|
102
|
+
foreign_key.options[:column].should eql('collection_id')
|
103
|
+
foreign_key.options[:dependent].should eql(@dependent)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe 'when creating tables with t.reference' do
|
108
|
+
|
109
|
+
it 'should accept a t.references constraint' do
|
110
|
+
create_table :items do |t|
|
111
|
+
t.string :name
|
112
|
+
t.references :collection, :foreign_key => true
|
113
|
+
end
|
114
|
+
|
115
|
+
foreign_key = @adapter.foreign_keys(:items)[0]
|
116
|
+
foreign_key.to_table.should eql('collections')
|
117
|
+
foreign_key.options[:primary_key].should eql('id')
|
118
|
+
foreign_key.options[:column].should eql('collection_id')
|
119
|
+
foreign_key.options[:dependent].should be_nil
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'should accept :foreign_key => { :dependent => :nullify }' do
|
123
|
+
@dependent = :nullify
|
124
|
+
create_table :items do |t|
|
125
|
+
t.string :name
|
126
|
+
t.references :collection, :foreign_key => {:dependent => @dependent}
|
127
|
+
end
|
128
|
+
|
129
|
+
foreign_key = @adapter.foreign_keys(:items)[0]
|
130
|
+
foreign_key.to_table.should eql('collections')
|
131
|
+
foreign_key.options[:primary_key].should eql('id')
|
132
|
+
foreign_key.options[:column].should eql('collection_id')
|
133
|
+
foreign_key.options[:dependent].should eql(@dependent)
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'should accept :foreign_key => { :dependent => :delete }' do
|
137
|
+
@dependent = :delete
|
138
|
+
create_table :items do |t|
|
139
|
+
t.string :name
|
140
|
+
t.references :collection, :foreign_key => {:dependent => @dependent}
|
141
|
+
end
|
142
|
+
|
143
|
+
foreign_key = @adapter.foreign_keys(:items)[0]
|
144
|
+
foreign_key.to_table.should eql('collections')
|
145
|
+
foreign_key.options[:primary_key].should eql('id')
|
146
|
+
foreign_key.options[:column].should eql('collection_id')
|
147
|
+
foreign_key.options[:dependent].should eql(@dependent)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
|