mover 0.1.1 → 0.2.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.
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mover do
4
+
5
+ describe :move_to do
6
+
7
+ before(:each) do
8
+ [ 1, 0, 1 ].each { |v| $db.migrate(v) }
9
+ @articles = create_records(Article)
10
+ @comments = create_records(Comment)
11
+ @articles[0].move_to(ArticleArchive)
12
+ Article.move_to(ArticleArchive, [ 'id = ?', 2 ])
13
+ end
14
+
15
+ describe 'move records' do
16
+
17
+ it "should move both articles and their associations" do
18
+ Article.count.should == 3
19
+ Comment.count.should == 3
20
+ ArticleArchive.count.should == 2
21
+ CommentArchive.count.should == 2
22
+ Article.find_by_id(1).nil?.should == true
23
+ Comment.find_by_id(2).nil?.should == true
24
+ ArticleArchive.find_by_id(1).nil?.should == false
25
+ CommentArchive.find_by_id(2).nil?.should == false
26
+ comments = ArticleArchive.find_by_id(1).comments
27
+ comments.length.should == 1
28
+ comments.first.id.should == 1
29
+ comments = ArticleArchive.find_by_id(2).comments
30
+ comments.length.should == 1
31
+ comments.first.id.should == 2
32
+ end
33
+
34
+ it "should assign moved_at" do
35
+ ArticleArchive.find_by_id(1).moved_at.utc.to_s.should == Time.now.utc.to_s
36
+ end
37
+ end
38
+
39
+ describe 'move records back' do
40
+
41
+ before(:each) do
42
+ ArticleArchive.find(1).move_to(Article)
43
+ ArticleArchive.move_to(Article, [ 'id = ?', 2 ])
44
+ end
45
+
46
+ it "should move both articles and their associations" do
47
+ Article.count.should == 5
48
+ Comment.count.should == 5
49
+ ArticleArchive.count.should == 0
50
+ CommentArchive.count.should == 0
51
+ Article.find_by_id(1).nil?.should == false
52
+ Comment.find_by_id(2).nil?.should == false
53
+ ArticleArchive.find_by_id(1).nil?.should == true
54
+ CommentArchive.find_by_id(2).nil?.should == true
55
+ comments = Article.find_by_id(1).comments
56
+ comments.length.should == 1
57
+ comments.first.id.should == 1
58
+ comments = Article.find_by_id(2).comments
59
+ comments.length.should == 1
60
+ comments.first.id.should == 2
61
+ end
62
+ end
63
+ end
64
+
65
+ describe :reserve_id do
66
+ it "should return an id" do
67
+ Article.reserve_id.class.should == Fixnum
68
+ end
69
+
70
+ it "should delete the record" do
71
+ id = Article.reserve_id
72
+ Article.find_by_id(id).should == nil
73
+ end
74
+ end
75
+ end
data/spec/spec_helper.rb CHANGED
@@ -24,7 +24,7 @@ def connection
24
24
  ActiveRecord::Base.connection
25
25
  end
26
26
 
27
- def create_records(klass=Article, values={})
27
+ def create_records(klass, values={})
28
28
  klass.delete_all
29
29
  (1..5).collect do |x|
30
30
  klass.column_names.each do |column|
@@ -37,12 +37,4 @@ def create_records(klass=Article, values={})
37
37
  values[:id] = x
38
38
  klass.create(values)
39
39
  end
40
- end
41
-
42
- def migrate_with_state(version)
43
- @old_article_columns = columns("articles")
44
- @old_archive_columns = columns("articles_archive")
45
- $db.migrate(version)
46
- @new_article_columns = columns("articles")
47
- @new_archive_columns = columns("articles_archive")
48
40
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mover
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Winton Welsh
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-04-01 00:00:00 -07:00
12
+ date: 2010-04-02 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -32,26 +32,20 @@ extra_rdoc_files:
32
32
  - README.markdown
33
33
  files:
34
34
  - init.rb
35
- - lib/mover/migrator.rb
36
- - lib/mover/record.rb
37
- - lib/mover/table.rb
38
35
  - lib/mover.rb
39
- - log/development.log
40
36
  - MIT-LICENSE
41
37
  - rails/init.rb
42
38
  - Rakefile
43
39
  - README.markdown
44
40
  - require.rb
45
41
  - spec/config/database.yml.example
46
- - spec/db/migrate/001_create_articles.rb
47
- - spec/db/migrate/002_add_permalink.rb
48
- - spec/db/migrate/003_remove_magic_columns.rb
42
+ - spec/db/migrate/001_create_fixtures.rb
49
43
  - spec/fixtures/article.rb
44
+ - spec/fixtures/article_archive.rb
50
45
  - spec/fixtures/comment.rb
46
+ - spec/fixtures/comment_archive.rb
51
47
  - spec/log/test.log
52
- - spec/mover/migrator_spec.rb
53
- - spec/mover/record_spec.rb
54
- - spec/mover/table_spec.rb
48
+ - spec/mover_spec.rb
55
49
  - spec/Rakefile
56
50
  - spec/spec_helper.rb
57
51
  has_rdoc: true
@@ -1,44 +0,0 @@
1
- module Mover
2
- module Migrator
3
-
4
- def method_missing_with_mover(method, *arguments, &block)
5
- args = Marshal.load(Marshal.dump(arguments))
6
- method_missing_without_mover(method, *arguments, &block)
7
-
8
- supported = [
9
- :add_column, :add_timestamps, :change_column,
10
- :change_column_default, :change_table,
11
- :drop_table, :remove_column, :remove_columns,
12
- :remove_timestamps, :rename_column, :rename_table
13
- ]
14
-
15
- # Don't change these columns
16
- %w(moved_at move_id).each do |column|
17
- return if args.include?(column) || args.include?(column.intern)
18
- end
19
-
20
- if !args.empty? && supported.include?(method)
21
- connection = ActiveRecord::Base.connection
22
- table_name = ActiveRecord::Migrator.proper_table_name(args[0])
23
- # Find model
24
- klass = Object.subclasses_of(ActiveRecord::Base).detect do |klass|
25
- if klass.respond_to?(:movable_types)
26
- klass.table_name.to_s == table_name
27
- end
28
- end
29
- # Run migration on movable table
30
- if klass
31
- klass.movable_types.each do |type|
32
- args[0] = [ table_name, type ].join('_')
33
- if method == :rename_table
34
- args[1] = [ args[1].to_s, type ].join('_')
35
- end
36
- if connection.table_exists?(args[0])
37
- connection.send(method, *args, &block)
38
- end
39
- end
40
- end
41
- end
42
- end
43
- end
44
- end
data/lib/mover/record.rb DELETED
@@ -1,114 +0,0 @@
1
- module Mover
2
- module Base
3
- module Record
4
- module ClassMethods
5
-
6
- def move_from(type, conditions)
7
- klass = movable_class(type)
8
- if klass
9
- if klass.column_names.include?('move_id')
10
- klass.find_each(:conditions => conditions) do |record|
11
- record.move_from
12
- end
13
- else
14
- execute_move(klass, self, conditions)
15
- end
16
- end
17
- end
18
-
19
- def move_to(type, conditions)
20
- if movable_class(type).column_names.include?('move_id')
21
- self.find_each(:conditions => conditions) do |record|
22
- record.move_to(type)
23
- end
24
- else
25
- execute_move(self, movable_class(type), conditions)
26
- end
27
- end
28
-
29
- private
30
-
31
- def execute_move(from_class, to_class, conditions, &block)
32
- add_conditions! where = '', conditions
33
- insert = from_class.column_names & to_class.column_names
34
- insert.collect! { |col| connection.quote_column_name(col) }
35
- select = insert.clone
36
- yield(insert, select) if block_given?
37
- if to_class.column_names.include?('moved_at')
38
- insert << connection.quote_column_name('moved_at')
39
- select << connection.quote(Time.now)
40
- end
41
- connection.execute(<<-SQL)
42
- INSERT INTO #{to_class.table_name} (#{insert.join(', ')})
43
- SELECT #{select.join(', ')}
44
- FROM #{from_class.table_name}
45
- #{where}
46
- SQL
47
- connection.execute("DELETE FROM #{from_class.table_name} #{where}")
48
- end
49
-
50
- def movable_class(type)
51
- eval(self.name + type.to_s.classify)
52
- rescue
53
- raise "#{self.table_name.classify} needs an `is_movable :#{type}` definition"
54
- end
55
- end
56
-
57
- module InstanceMethods
58
-
59
- def move_from
60
- return unless self.respond_to?(:moved_from_class)
61
- # Move associations
62
- moved_from_class.reflect_on_all_associations.each do |association|
63
- if move_association?(association)
64
- klass = association.klass.send(:movable_class, self.class.movable_type)
65
- klass.find_each(:conditions => [ 'move_id = ?', self.move_id ]) do |record|
66
- record.move_from
67
- end
68
- end
69
- end
70
- # Move record
71
- conditions = "#{self.class.primary_key} = #{id}"
72
- moved_from_class.send(:execute_move, self.class, moved_from_class, conditions)
73
- end
74
-
75
- def move_to(type)
76
- return if self.respond_to?(:moved_from_class)
77
- klass = self.class.send :movable_class, type
78
- if klass
79
- # Create movable_id
80
- if !self.movable_id && klass.column_names.include?('move_id')
81
- self.movable_id = Digest::MD5.hexdigest("#{self.class.name}#{self.id}")
82
- end
83
- # Move associations
84
- self.class.reflect_on_all_associations.each do |association|
85
- if move_association?(association)
86
- self.send(association.name).each do |record|
87
- record.movable_id = self.movable_id
88
- record.move_to(type)
89
- end
90
- end
91
- end
92
- # Move record
93
- me = self
94
- conditions = "#{self.class.primary_key} = #{id}"
95
- self.class.send(:execute_move, self.class, klass, conditions) do |insert, select|
96
- if me.movable_id
97
- insert << connection.quote_column_name('move_id')
98
- select << connection.quote(self.movable_id)
99
- end
100
- end
101
- self.movable_id = nil
102
- end
103
- end
104
-
105
- private
106
-
107
- def move_association?(association)
108
- association.klass.respond_to?(:movable_types) &&
109
- association.macro.to_s =~ /^has/
110
- end
111
- end
112
- end
113
- end
114
- end
data/lib/mover/table.rb DELETED
@@ -1,82 +0,0 @@
1
- module Mover
2
- module Base
3
- module Table
4
-
5
- def create_movable_table(type, options={})
6
- movable_table = [ table_name, type ].join('_')
7
- columns =
8
- if options[:columns]
9
- options[:columns].collect { |c| "`#{c}`" }.join(', ')
10
- else
11
- '*'
12
- end
13
- engine = options[:engine]
14
- engine ||=
15
- if connection.class.to_s.include?('Mysql')
16
- "ENGINE=InnoDB"
17
- end
18
- if table_exists? and !connection.table_exists?(movable_table)
19
- # Create table
20
- connection.execute(<<-SQL)
21
- CREATE TABLE #{movable_table} #{engine}
22
- AS SELECT #{columns}
23
- FROM #{table_name}
24
- WHERE false;
25
- SQL
26
- # Create indexes
27
- options[:indexes] ||= indexed_columns(table_name)
28
- options[:indexes].each do |column|
29
- connection.add_index(movable_table, column)
30
- end
31
- end
32
- end
33
-
34
- def drop_movable_table(*types)
35
- types.each do |type|
36
- connection.execute("DROP TABLE IF EXISTS #{[ table_name, type ].join('_')}")
37
- end
38
- end
39
-
40
- private
41
-
42
- def indexed_columns(table_name)
43
- # MySQL
44
- if connection.class.to_s.include?('Mysql')
45
- index_query = "SHOW INDEX FROM #{table_name}"
46
- indexes = connection.select_all(index_query).collect do |r|
47
- r["Column_name"]
48
- end
49
- # PostgreSQL
50
- # http://stackoverflow.com/questions/2204058/show-which-columns-an-index-is-on-in-postgresql/2213199
51
- elsif connection.class.to_s.include?('PostgreSQL')
52
- index_query = <<-SQL
53
- select
54
- t.relname as table_name,
55
- i.relname as index_name,
56
- a.attname as column_name
57
- from
58
- pg_class t,
59
- pg_class i,
60
- pg_index ix,
61
- pg_attribute a
62
- where
63
- t.oid = ix.indrelid
64
- and i.oid = ix.indexrelid
65
- and a.attrelid = t.oid
66
- and a.attnum = ANY(ix.indkey)
67
- and t.relkind = 'r'
68
- and t.relname = '#{table_name}'
69
- order by
70
- t.relname,
71
- i.relname
72
- SQL
73
- indexes = connection.select_all(index_query).collect do |r|
74
- r["column_name"]
75
- end
76
- else
77
- raise 'Mover does not support this database adapter'
78
- end
79
- end
80
- end
81
- end
82
- end
data/log/development.log DELETED
@@ -1,6 +0,0 @@
1
- SQL (0.2ms) SET SQL_AUTO_IS_NULL=0
2
- User Load (59.6ms) SELECT * FROM `users` ORDER BY users.id DESC LIMIT 1
3
- User Columns (21.6ms) SHOW FIELDS FROM `users`
4
- SQL (0.3ms) SET SQL_AUTO_IS_NULL=0
5
- SQL (0.3ms) SHOW TABLES
6
- User Columns (13.0ms) SHOW FIELDS FROM `users`
@@ -1,34 +0,0 @@
1
- class CreateArticles < ActiveRecord::Migration
2
- def self.up
3
- create_table :articles do |t|
4
- t.string :title
5
- t.string :body
6
- t.boolean :read
7
- end
8
- add_index :articles, :title
9
-
10
- Article.create_movable_table(:archive)
11
- add_column :articles_archive, :move_id, :string
12
- add_column :articles_archive, :moved_at, :datetime
13
-
14
- Article.create_movable_table(:draft)
15
-
16
- create_table :comments do |t|
17
- t.string :title
18
- t.string :body
19
- t.boolean :read
20
- t.integer :article_id
21
- end
22
-
23
- Comment.create_movable_table(:archive)
24
- add_column :comments_archive, :move_id, :string
25
- add_column :comments_archive, :moved_at, :datetime
26
- end
27
-
28
- def self.down
29
- drop_table :articles
30
- drop_table :comments
31
- Article.drop_movable_table(:archive)
32
- Comment.drop_movable_table(:archive)
33
- end
34
- end
@@ -1,9 +0,0 @@
1
- class AddPermalink < ActiveRecord::Migration
2
- def self.up
3
- add_column :articles, :permalink, :string
4
- end
5
-
6
- def self.down
7
- remove_column :articles, :permalink
8
- end
9
- end
@@ -1,9 +0,0 @@
1
- class RemoveMagicColumns < ActiveRecord::Migration
2
- def self.up
3
- remove_column :articles, :move_id
4
- remove_column :articles, :moved_at
5
- end
6
-
7
- def self.down
8
- end
9
- end
@@ -1,34 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
-
3
- describe Mover::Migrator do
4
-
5
- before(:each) do
6
- $db.migrate(1)
7
- $db.migrate(0)
8
- $db.migrate(1)
9
- end
10
-
11
- describe :method_missing_with_mover do
12
-
13
- it 'should migrate both tables up' do
14
- migrate_with_state(2)
15
- (@new_article_columns - @old_article_columns).should == [ 'permalink' ]
16
- (@new_archive_columns - @old_archive_columns).should == [ 'permalink' ]
17
- end
18
-
19
- it 'should migrate both tables down' do
20
- $db.migrate(2)
21
- migrate_with_state(1)
22
- (@old_article_columns - @new_article_columns).should == [ 'permalink' ]
23
- (@old_archive_columns - @new_archive_columns).should == [ 'permalink' ]
24
- end
25
-
26
- it "should not touch the archive's move_id or moved_at column" do
27
- connection.add_column(:articles, :move_id, :integer)
28
- connection.add_column(:articles, :moved_at, :datetime)
29
- migrate_with_state(3)
30
- (@old_article_columns - @new_article_columns).should == [ 'move_id', 'moved_at' ]
31
- (@old_archive_columns - @new_archive_columns).should == []
32
- end
33
- end
34
- end
@@ -1,156 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
-
3
- describe Mover::Base::Record do
4
-
5
- before(:all) do
6
- $db.migrate(1)
7
- $db.migrate(0)
8
- $db.migrate(1)
9
- end
10
-
11
- describe :InstanceMethods do
12
- describe :move_to do
13
-
14
- before(:all) do
15
- @articles = create_records
16
- @comments = create_records(Comment)
17
- @articles[0..1].each do |a|
18
- a.move_to(:archive)
19
- end
20
- end
21
-
22
- it "should move some records to the archive table" do
23
- Article.count.should == 3
24
- ArticleArchive.count.should == 2
25
- end
26
-
27
- it "should preserve record attributes" do
28
- 2.times do |x|
29
- original = @articles[x]
30
- copy = ArticleArchive.find(original.id)
31
- record_match?(original, copy)
32
- end
33
- end
34
-
35
- it "should move associated records" do
36
- Comment.count.should == 3
37
- CommentArchive.count.should == 2
38
- end
39
-
40
- it "should preserve associated record attributes" do
41
- 2.times do |x|
42
- original = @comments[x]
43
- copy = CommentArchive.find(original.id)
44
- record_match?(original, copy)
45
- end
46
- end
47
-
48
- it "should populate move_id" do
49
- (1..2).each do |x|
50
- article = ArticleArchive.find(x)
51
- comment = CommentArchive.find(x)
52
- comment.move_id.nil?.should == false
53
- comment.move_id.length.should == 32
54
- comment.move_id.should == article.move_id
55
- end
56
- end
57
-
58
- it "should populate moved_at" do
59
- (1..2).each do |x|
60
- article = ArticleArchive.find(x)
61
- comment = CommentArchive.find(x)
62
- comment.moved_at.nil?.should == false
63
- comment.moved_at.should == article.moved_at
64
- end
65
- end
66
- end
67
-
68
- describe :move_from do
69
-
70
- before(:all) do
71
- articles = create_records
72
- create_records(Comment)
73
- articles[0..1].each do |a|
74
- a.move_to(:archive)
75
- end
76
- @articles = ArticleArchive.find(1, 2)
77
- @comments = CommentArchive.find(1, 2)
78
- @articles.each do |article|
79
- article.move_from
80
- end
81
- end
82
-
83
- it "should move records back to the original table" do
84
- Article.count.should == 5
85
- ArticleArchive.count.should == 0
86
- end
87
-
88
- it "should preserve record attributes" do
89
- 2.times do |x|
90
- original = @articles[x]
91
- copy = Article.find(original.id)
92
- record_match?(original, copy)
93
- end
94
- end
95
-
96
- it "should move associated records" do
97
- Comment.count.should == 5
98
- CommentArchive.count.should == 0
99
- end
100
-
101
- it "should preserve associated record attributes" do
102
- 2.times do |x|
103
- original = @comments[x]
104
- copy = Comment.find(original.id)
105
- record_match?(original, copy)
106
- end
107
- end
108
- end
109
- end
110
-
111
- describe :ClassMethods do
112
- describe :move_to do
113
-
114
- before(:all) do
115
- create_records
116
- create_records(Comment)
117
- Article.move_to(:archive, [ 'id = ? OR id = ?', 1, 2 ])
118
- Article.move_to(:draft, [ 'id = ? OR id = ?', 3, 4 ])
119
- end
120
-
121
- it "should move the records" do
122
- Article.count.should == 1
123
- ArticleArchive.count.should == 2
124
- ArticleDraft.count.should == 2
125
- end
126
-
127
- it "should move associated records" do
128
- Comment.count.should == 3
129
- CommentArchive.count.should == 2
130
- end
131
- end
132
-
133
- describe :move_from do
134
-
135
- before(:all) do
136
- create_records
137
- create_records(Comment)
138
- Article.move_to(:archive, [ 'id = ? OR id = ?', 1, 2 ])
139
- Article.move_to(:draft, [ 'id = ? OR id = ?', 3, 4 ])
140
- Article.move_from(:archive, [ 'id = ? OR id = ?', 1, 2 ])
141
- Article.move_from(:draft, [ 'id = ? OR id = ?', 3, 4 ])
142
- end
143
-
144
- it "should move the records" do
145
- Article.count.should == 5
146
- ArticleArchive.count.should == 0
147
- ArticleDraft.count.should == 0
148
- end
149
-
150
- it "should move associated records" do
151
- Comment.count.should == 5
152
- CommentArchive.count.should == 0
153
- end
154
- end
155
- end
156
- end