automatic_foreign_key 1.0.2 → 1.0.5

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/Rakefile CHANGED
@@ -12,7 +12,7 @@ constraints when creating tables. It uses SQL-92 syntax and as such should be co
12
12
  gem.email = "michal.lomnicki@gmail.com"
13
13
  gem.homepage = "http://github.com/mlomnicki/automatic_foreign_key"
14
14
  gem.authors = ["Michał Łomnicki"]
15
- gem.add_dependency "redhillonrails_core", ">= 1.0.2"
15
+ gem.add_dependency "redhillonrails_core", ">= 1.0.4.1"
16
16
  gem.add_dependency "activerecord", ">= 2.2"
17
17
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
18
18
  end
@@ -41,9 +41,32 @@ rescue LoadError
41
41
  end
42
42
  end
43
43
 
44
- task :test => :check_dependencies
44
+ require 'spec/rake/spectask'
45
+ %w[postgresql mysql].each do |adapter|
46
+ namespace adapter do
47
+ Spec::Rake::SpecTask.new(:spec) do |spec|
48
+ spec.libs << 'lib' << 'spec' << "spec/connections/#{adapter}"
49
+ spec.spec_files = FileList['spec/**/*_spec.rb']
50
+ end
51
+ end
52
+ end
53
+
54
+ desc 'Run postgresql and mysql tests'
55
+ task :spec do
56
+ %w[postgresql mysql].each do |adapter|
57
+ Rake::Task["#{adapter}:spec"].invoke
58
+ end
59
+ end
60
+
61
+ task :spec => :check_dependencies
45
62
 
46
- task :default => :test
63
+ task :default => :spec
64
+
65
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
66
+ spec.libs << 'lib' << 'spec'
67
+ spec.pattern = 'spec/**/*_spec.rb'
68
+ spec.rcov = true
69
+ end
47
70
 
48
71
  require 'rake/rdoctask'
49
72
  Rake::RDocTask.new do |rdoc|
@@ -54,3 +77,44 @@ Rake::RDocTask.new do |rdoc|
54
77
  rdoc.rdoc_files.include('README*')
55
78
  rdoc.rdoc_files.include('lib/**/*.rb')
56
79
  end
80
+
81
+ namespace :postgresql do
82
+ desc 'Build the PostgreSQL test databases'
83
+ task :build_databases do
84
+ %x( createdb -E UTF8 afk_unittest )
85
+ %x( createdb -E UTF8 afk_unittest2 )
86
+ end
87
+
88
+ desc 'Drop the PostgreSQL test databases'
89
+ task :drop_databases do
90
+ %x( dropdb afk_unittest )
91
+ %x( dropdb afk_unittest2 )
92
+ end
93
+
94
+ desc 'Rebuild the PostgreSQL test databases'
95
+ task :rebuild_databases => [:drop_databases, :build_databases]
96
+ end
97
+
98
+ task :build_postgresql_databases => 'postgresql:build_databases'
99
+ task :drop_postgresql_databases => 'postgresql:drop_databases'
100
+ task :rebuild_postgresql_databases => 'postgresql:rebuild_databases'
101
+
102
+ MYSQL_DB_USER = 'afk'
103
+ namespace :mysql do
104
+ desc 'Build the MySQL test databases'
105
+ task :build_databases do
106
+ %x( echo "create DATABASE afk_unittest DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_unicode_ci " | mysql --user=#{MYSQL_DB_USER})
107
+ end
108
+
109
+ desc 'Drop the MySQL test databases'
110
+ task :drop_databases do
111
+ %x( mysqladmin --user=#{MYSQL_DB_USER} -f drop afk_unittest )
112
+ end
113
+
114
+ desc 'Rebuild the MySQL test databases'
115
+ task :rebuild_databases => [:drop_databases, :build_databases]
116
+ end
117
+
118
+ task :build_mysql_databases => 'mysql:build_databases'
119
+ task :drop_mysql_databases => 'mysql:drop_databases'
120
+ task :rebuild_mysql_databases => 'mysql:rebuild_databases'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.2
1
+ 1.0.5
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{automatic_foreign_key}
8
- s.version = "1.0.2"
8
+ s.version = "1.0.5"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Michał Łomnicki"]
12
- s.date = %q{2010-03-30}
12
+ s.date = %q{2010-04-06}
13
13
  s.description = %q{Automatic Key Migrations is a gem that automatically generates foreign-key
14
14
  constraints when creating tables. It uses SQL-92 syntax and as such should be compatible with most databases that support foreign-key constraints.}
15
15
  s.email = %q{michal.lomnicki@gmail.com}
@@ -32,27 +32,51 @@ constraints when creating tables. It uses SQL-92 syntax and as such should be co
32
32
  "lib/automatic_foreign_key/active_record/connection_adapters/table_definition.rb",
33
33
  "lib/automatic_foreign_key/active_record/migration.rb",
34
34
  "lib/generators/automatic_foreign_key/migration_generator.rb",
35
- "lib/generators/automatic_foreign_key/templates/migration.rb"
35
+ "lib/generators/automatic_foreign_key/templates/migration.rb",
36
+ "spec/aaa_create_tables_spec.rb",
37
+ "spec/connections/mysql/connection.rb",
38
+ "spec/connections/postgresql/connection.rb",
39
+ "spec/migration_spec.rb",
40
+ "spec/models/comment.rb",
41
+ "spec/models/post.rb",
42
+ "spec/models/user.rb",
43
+ "spec/references_spec.rb",
44
+ "spec/schema/schema.rb",
45
+ "spec/spec_helper.rb",
46
+ "spec/support/matchers/automatic_foreign_key_matchers.rb"
36
47
  ]
37
48
  s.homepage = %q{http://github.com/mlomnicki/automatic_foreign_key}
38
49
  s.rdoc_options = ["--charset=UTF-8"]
39
50
  s.require_paths = ["lib"]
40
51
  s.rubygems_version = %q{1.3.6}
41
52
  s.summary = %q{Automatically generate foreign-key constraints when creating tables}
53
+ s.test_files = [
54
+ "spec/schema/schema.rb",
55
+ "spec/connections/postgresql/connection.rb",
56
+ "spec/connections/mysql/connection.rb",
57
+ "spec/aaa_create_tables_spec.rb",
58
+ "spec/support/matchers/automatic_foreign_key_matchers.rb",
59
+ "spec/spec_helper.rb",
60
+ "spec/references_spec.rb",
61
+ "spec/migration_spec.rb",
62
+ "spec/models/user.rb",
63
+ "spec/models/post.rb",
64
+ "spec/models/comment.rb"
65
+ ]
42
66
 
43
67
  if s.respond_to? :specification_version then
44
68
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
45
69
  s.specification_version = 3
46
70
 
47
71
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
48
- s.add_runtime_dependency(%q<redhillonrails_core>, [">= 1.0.2"])
72
+ s.add_runtime_dependency(%q<redhillonrails_core>, [">= 1.0.4.1"])
49
73
  s.add_runtime_dependency(%q<activerecord>, [">= 2.2"])
50
74
  else
51
- s.add_dependency(%q<redhillonrails_core>, [">= 1.0.2"])
75
+ s.add_dependency(%q<redhillonrails_core>, [">= 1.0.4.1"])
52
76
  s.add_dependency(%q<activerecord>, [">= 2.2"])
53
77
  end
54
78
  else
55
- s.add_dependency(%q<redhillonrails_core>, [">= 1.0.2"])
79
+ s.add_dependency(%q<redhillonrails_core>, [">= 1.0.4.1"])
56
80
  s.add_dependency(%q<activerecord>, [">= 2.2"])
57
81
  end
58
82
  end
@@ -1,10 +1,24 @@
1
1
  module AutomaticForeignKey::ActiveRecord
2
2
  module Base
3
- def self.included(base)
3
+ def self.included(base) # :nodoc
4
4
  base.extend(ClassMethods)
5
5
  end
6
6
 
7
7
  module ClassMethods
8
+ # Determines referenced table and column.
9
+ # Used in migrations.
10
+ # references('comments', 'post_id') # => ['posts', 'id']
11
+ #
12
+ # If <tt>column_name</tt> is parent_id it references to the same table
13
+ # references('pages', 'parent_id') # => ['pages', 'id']
14
+ #
15
+ # If referenced table cannot be determined properly it may be overriden
16
+ # references('widgets', 'main_page_id', :references => 'pages'))
17
+ # # => ['pages', 'id']
18
+ #
19
+ # Also whole result may be given by hand
20
+ # references('addresses', 'member_id', :references => ['users', 'uuid'])
21
+ # # => ['users', 'uuid']
8
22
  def references(table_name, column_name, options = {})
9
23
  column_name = column_name.to_s
10
24
  if options.has_key?(:references)
@@ -5,6 +5,20 @@ module AutomaticForeignKey::ActiveRecord
5
5
  end
6
6
 
7
7
  module ClassMethods
8
+ # Overrides standard ActiveRecord add column and adds
9
+ # foreign key if column references other column
10
+ #
11
+ # add_column('comments', 'post_id', :integer)
12
+ # # creates a column and adds foreign key on posts(id)
13
+ #
14
+ # add_column('addresses', 'citizen_id', :integer, :references => :users
15
+ # # creates a column and adds foreign key on users(id)
16
+ #
17
+ # add_column('addresses', 'citizen_id', :integer, :references => [:users, :uuid]
18
+ # # creates a column and adds foreign key on users(uuid)
19
+ #
20
+ # add_column('users', 'verified')
21
+ # # just creates a column as usually
8
22
  def add_column(table_name, column_name, type, options = {})
9
23
  super
10
24
  references = ActiveRecord::Base.references(table_name, column_name, options)
@@ -1,4 +1,5 @@
1
1
  begin
2
+ require 'active_support'
2
3
  require 'redhillonrails_core'
3
4
  rescue
4
5
  gem 'redhillonrails_core'
@@ -0,0 +1,9 @@
1
+ # encoding: utf-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3
+
4
+ # This is not a test really. It just here to create schema
5
+ # The filename begins with "aaa" to ensure this is executed initially
6
+
7
+ ActiveRecord::Migration.suppress_messages do
8
+ load_schema
9
+ end
@@ -0,0 +1,18 @@
1
+ print "Using MySQL\n"
2
+ require 'logger'
3
+
4
+ ActiveRecord::Base.logger = Logger.new("debug.log")
5
+
6
+ ActiveRecord::Base.configurations = {
7
+ 'afk' => {
8
+ :adapter => 'mysql',
9
+ :database => 'afk_unittest',
10
+ :username => 'afk',
11
+ :encoding => 'utf8',
12
+ :socket => '/var/run/mysqld/mysqld.sock',
13
+ :min_messages => 'warning'
14
+ }
15
+
16
+ }
17
+
18
+ ActiveRecord::Base.establish_connection 'afk'
@@ -0,0 +1,15 @@
1
+ print "Using PostgreSQL\n"
2
+ require 'logger'
3
+
4
+ ActiveRecord::Base.logger = Logger.new("debug.log")
5
+
6
+ ActiveRecord::Base.configurations = {
7
+ 'afk' => {
8
+ :adapter => 'postgresql',
9
+ :database => 'afk_unittest',
10
+ :min_messages => 'warning'
11
+ }
12
+
13
+ }
14
+
15
+ ActiveRecord::Base.establish_connection 'afk'
@@ -0,0 +1,100 @@
1
+ # encoding: utf-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3
+
4
+ require 'models/post'
5
+ require 'models/comment'
6
+
7
+ describe ActiveRecord::Base do
8
+
9
+ it "should respond to references" do
10
+ ActiveRecord::Base.should respond_to :references
11
+ end
12
+
13
+ end
14
+
15
+ describe ActiveRecord::Migration do
16
+
17
+ context "when table is created" do
18
+ it "should create foreign keys" do
19
+ create_table(Post, :user_id => {},
20
+ :author_id => { :references => :users },
21
+ :member_id => { :references => nil } )
22
+ Post.should reference(:users, :id).on(:user_id)
23
+ Post.should reference(:users, :id).on(:author_id)
24
+ Post.should_not reference.on(:member_id)
25
+ end
26
+
27
+ end
28
+
29
+ context "when column is added" do
30
+
31
+ before(:all) do
32
+ @model = Comment
33
+ end
34
+
35
+ it "should create foreign key" do
36
+ add_column(:post_id, :integer) do
37
+ @model.should reference(:posts, :id).on(:post_id)
38
+ end
39
+ end
40
+
41
+ it "should create foreign key to explicity given table" do
42
+ add_column(:author_id, :integer, :references => :users) do
43
+ @model.should reference(:users, :id).on(:author_id)
44
+ end
45
+ end
46
+
47
+ it "should create foreign key to explicity given table and column name" do
48
+ add_column(:author_login, :string, :references => [:users, :login]) do
49
+ @model.should reference(:users, :login).on(:author_login)
50
+ end
51
+ end
52
+
53
+ it "should create foreign key to the same table on parent_id" do
54
+ add_column(:parent_id, :integer) do
55
+ @model.should reference(@model.table_name, :id).on(:parent_id)
56
+ end
57
+ end
58
+
59
+ it "shouldn't create foreign key if column doesn't look like foreign key" do
60
+ add_column(:views_count, :integer) do
61
+ @model.should_not reference.on(:views_count)
62
+ end
63
+ end
64
+
65
+ it "shouldnt't create foreign key if specified explicity" do
66
+ add_column(:post_id, :integer, :references => nil) do
67
+ @model.should_not reference.on(:post_id)
68
+ end
69
+ end
70
+
71
+ def add_column(column_name, *args)
72
+ table = @model.table_name
73
+ ActiveRecord::Migration.suppress_messages do
74
+ ActiveRecord::Migration.add_column(table, column_name, *args)
75
+ @model.reset_column_information
76
+ yield if block_given?
77
+ ActiveRecord::Migration.remove_column(table, column_name)
78
+ end
79
+ end
80
+
81
+ end
82
+
83
+ def foreign_key(model, column)
84
+ columns = Array(column)
85
+ model.foreign_keys.detect { |fk| fk.table_name == model.table_name && fk.column_names == columns }
86
+ end
87
+
88
+ def create_table(model, columns_with_options)
89
+ ActiveRecord::Migration.suppress_messages do
90
+ ActiveRecord::Migration.create_table model.table_name, :force => true do |t|
91
+ columns_with_options.each_pair do |column, options|
92
+ t.integer column, options
93
+ end
94
+ end
95
+ model.reset_column_information
96
+ end
97
+ end
98
+
99
+ end
100
+
@@ -0,0 +1,3 @@
1
+ class Comment < ActiveRecord::Base
2
+ belongs_to :post
3
+ end
@@ -0,0 +1,3 @@
1
+ class Post < ActiveRecord::Base
2
+ has_many :comments
3
+ end
@@ -0,0 +1,2 @@
1
+ class User < ActiveRecord::Base
2
+ end
@@ -0,0 +1,48 @@
1
+ # encoding: utf-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3
+
4
+ describe 'references method' do
5
+
6
+ before(:all) do
7
+ @target = ActiveRecord::Base
8
+ @table_name = 'comments'
9
+ @column_name = 'post_id'
10
+ @destination_table = 'posts'
11
+ @destinantion_column = :id
12
+ end
13
+
14
+ it "should accept table name and column name to references" do
15
+ lambda { @target.references(@table_name, @column_name) }.should_not raise_error
16
+ end
17
+
18
+ it "should return an array" do
19
+ @target.references(@table_name, @column_name).should be_an(Array)
20
+ end
21
+
22
+ it "should split column name to table name and primary key" do
23
+ result = @target.references(@table_name, @column_name)
24
+ result[0].should eql @destination_table
25
+ result[1].should eql @destinantion_column
26
+ end
27
+
28
+ it "should handle parent_id as belonging to the same table" do
29
+ column_name = 'parent_id'
30
+ result = @target.references(@table_name, column_name)
31
+ result[0].should eql @table_name
32
+ result[1].should eql :id
33
+ end
34
+
35
+ it "should accept :references option which overrides default table name" do
36
+ result = @target.references(@table_name, @column_name, :references => 'users')
37
+ result[0].should eql 'users'
38
+ result[1].should eql :id
39
+ end
40
+
41
+ it "should accept :references option which overrides default table name and default column name" do
42
+ result = @target.references(@table_name, @column_name, :references => ['users', 'uuid'])
43
+ result[0].should eql 'users'
44
+ result[1].should eql 'uuid'
45
+ end
46
+
47
+ end
48
+
@@ -0,0 +1,16 @@
1
+ ActiveRecord::Schema.define do
2
+
3
+ create_table :users, :force => true do |t|
4
+ t.string :login
5
+ end
6
+ add_index :users, :login, :unique => true
7
+
8
+ create_table :comments, :force => true do |t|
9
+ t.string :content
10
+ end
11
+
12
+ create_table :posts, :force => true do |t|
13
+ t.string :content
14
+ end
15
+
16
+ end
@@ -0,0 +1,16 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'rubygems'
4
+ require 'automatic_foreign_key'
5
+ require 'spec'
6
+ require 'spec/autorun'
7
+ require 'connection'
8
+ Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each {|f| require f}
9
+
10
+ Spec::Runner.configure do |config|
11
+ config.include(AutomaticForeignKeyMatchers)
12
+ end
13
+
14
+ def load_schema
15
+ eval(File.read(File.join(File.dirname(__FILE__), 'schema', 'schema.rb')))
16
+ end
@@ -0,0 +1,52 @@
1
+ module AutomaticForeignKeyMatchers
2
+
3
+ class Reference
4
+ def initialize(expected)
5
+ @column_names = nil
6
+ unless expected.empty?
7
+ @references_column_names = Array(expected).collect(&:to_s)
8
+ @references_table_name = @references_column_names.shift
9
+ end
10
+ end
11
+
12
+ def matches?(model)
13
+ @model = model
14
+ if @references_table_name
15
+ @result = @model.foreign_keys.select do |fk|
16
+ fk.references_table_name == @references_table_name &&
17
+ fk.references_column_names == @references_column_names
18
+ end
19
+ else
20
+ @result = @model.foreign_keys
21
+ end
22
+ if @column_names
23
+ @result.any? { |fk| fk.column_names == @column_names }
24
+ else
25
+ !!@result
26
+ end
27
+ end
28
+
29
+ def failure_message_for_should(should_not = false)
30
+ target_column_names = @column_names.present? ? "(#{@column_names.join(', ')})" : ""
31
+ destinantion_column_names = @references_table_name ? "#{@references_table_name}(#{@references_column_names.join(', ')})" : "anything"
32
+ invert = should_not ? 'not' : ''
33
+ "Expected #{@model.table_name}#{target_column_names} #{invert} to reference #{destinantion_column_names}"
34
+ end
35
+
36
+ def failure_message_for_should_not
37
+ failure_message_for_should(true)
38
+ end
39
+
40
+ def on(*column_names)
41
+ @column_names = column_names.collect(&:to_s)
42
+ self
43
+ end
44
+
45
+ end
46
+
47
+ def reference(*expect)
48
+ Reference.new(expect)
49
+ end
50
+
51
+ end
52
+
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 1
7
7
  - 0
8
- - 2
9
- version: 1.0.2
8
+ - 5
9
+ version: 1.0.5
10
10
  platform: ruby
11
11
  authors:
12
12
  - "Micha\xC5\x82 \xC5\x81omnicki"
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-03-30 00:00:00 +02:00
17
+ date: 2010-04-06 00:00:00 +02:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -27,8 +27,9 @@ dependencies:
27
27
  segments:
28
28
  - 1
29
29
  - 0
30
- - 2
31
- version: 1.0.2
30
+ - 4
31
+ - 1
32
+ version: 1.0.4.1
32
33
  type: :runtime
33
34
  version_requirements: *id001
34
35
  - !ruby/object:Gem::Dependency
@@ -71,6 +72,17 @@ files:
71
72
  - lib/automatic_foreign_key/active_record/migration.rb
72
73
  - lib/generators/automatic_foreign_key/migration_generator.rb
73
74
  - lib/generators/automatic_foreign_key/templates/migration.rb
75
+ - spec/aaa_create_tables_spec.rb
76
+ - spec/connections/mysql/connection.rb
77
+ - spec/connections/postgresql/connection.rb
78
+ - spec/migration_spec.rb
79
+ - spec/models/comment.rb
80
+ - spec/models/post.rb
81
+ - spec/models/user.rb
82
+ - spec/references_spec.rb
83
+ - spec/schema/schema.rb
84
+ - spec/spec_helper.rb
85
+ - spec/support/matchers/automatic_foreign_key_matchers.rb
74
86
  has_rdoc: true
75
87
  homepage: http://github.com/mlomnicki/automatic_foreign_key
76
88
  licenses: []
@@ -101,5 +113,15 @@ rubygems_version: 1.3.6
101
113
  signing_key:
102
114
  specification_version: 3
103
115
  summary: Automatically generate foreign-key constraints when creating tables
104
- test_files: []
105
-
116
+ test_files:
117
+ - spec/schema/schema.rb
118
+ - spec/connections/postgresql/connection.rb
119
+ - spec/connections/mysql/connection.rb
120
+ - spec/aaa_create_tables_spec.rb
121
+ - spec/support/matchers/automatic_foreign_key_matchers.rb
122
+ - spec/spec_helper.rb
123
+ - spec/references_spec.rb
124
+ - spec/migration_spec.rb
125
+ - spec/models/user.rb
126
+ - spec/models/post.rb
127
+ - spec/models/comment.rb