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.
- data/README.markdown +31 -56
- data/lib/mover.rb +71 -52
- data/require.rb +4 -8
- data/spec/db/migrate/001_create_fixtures.rb +28 -0
- data/spec/fixtures/article.rb +3 -1
- data/spec/fixtures/article_archive.rb +6 -0
- data/spec/fixtures/comment.rb +0 -1
- data/spec/fixtures/comment_archive.rb +3 -0
- data/spec/log/test.log +4967 -19176
- data/spec/mover_spec.rb +75 -0
- data/spec/spec_helper.rb +1 -9
- metadata +6 -12
- data/lib/mover/migrator.rb +0 -44
- data/lib/mover/record.rb +0 -114
- data/lib/mover/table.rb +0 -82
- data/log/development.log +0 -6
- data/spec/db/migrate/001_create_articles.rb +0 -34
- data/spec/db/migrate/002_add_permalink.rb +0 -9
- data/spec/db/migrate/003_remove_magic_columns.rb +0 -9
- data/spec/mover/migrator_spec.rb +0 -34
- data/spec/mover/record_spec.rb +0 -156
- data/spec/mover/table_spec.rb +0 -80
data/README.markdown
CHANGED
@@ -10,86 +10,61 @@ Requirements
|
|
10
10
|
sudo gem install mover
|
11
11
|
</pre>
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
Create the movable table
|
16
|
-
------------------------
|
17
|
-
|
18
|
-
Migration:
|
13
|
+
Move records
|
14
|
+
------------
|
19
15
|
|
20
16
|
<pre>
|
21
|
-
|
22
|
-
|
23
|
-
Article.create_movable_table(
|
24
|
-
:archive,
|
25
|
-
:columns => %w(id title body created_at),
|
26
|
-
:indexes => %w(id created_at)
|
27
|
-
)
|
28
|
-
add_column :articles_archive, :move_id, :string
|
29
|
-
add_column :articles_archive, :moved_at, :datetime
|
30
|
-
end
|
31
|
-
|
32
|
-
def self.down
|
33
|
-
Article.drop_movable_table(:archive)
|
34
|
-
end
|
35
|
-
end
|
17
|
+
Article.last.move_to(ArticleArchive)
|
18
|
+
Article.move_to(ArticleArchive, [ "created_at > ?", Date.today ])
|
36
19
|
</pre>
|
37
20
|
|
38
|
-
The
|
39
|
-
|
40
|
-
Options:
|
21
|
+
The <code>move_to</code> method is available to all models.
|
41
22
|
|
42
|
-
|
43
|
-
* <code>:indexes</code> - Only create certain indexes. Defaults to all.
|
23
|
+
The two tables do not have to be identical. Only shared columns transfer.
|
44
24
|
|
45
|
-
|
25
|
+
Callbacks
|
26
|
+
---------
|
46
27
|
|
47
|
-
|
28
|
+
In this example, we want an "archive" table for articles and comments.
|
48
29
|
|
49
|
-
|
50
|
-
----------------
|
30
|
+
We also want the article's comments to be archived when the article is.
|
51
31
|
|
52
32
|
<pre>
|
53
33
|
class Article < ActiveRecord::Base
|
54
|
-
|
34
|
+
has_many :comments
|
35
|
+
before_move_to :ArticleArchive do
|
36
|
+
comments.each { |c| c.move_to(CommentArchive) }
|
37
|
+
end
|
55
38
|
end
|
56
|
-
</pre>
|
57
39
|
|
58
|
-
|
40
|
+
class ArticleArchive < ActiveRecord::Base
|
41
|
+
has_many :comments, :class_name => 'CommentArchive', :foreign_key => 'article_id'
|
42
|
+
before_move_to :Article do
|
43
|
+
comments.each { |c| c.move_to(Comment) }
|
44
|
+
end
|
45
|
+
end
|
59
46
|
|
60
|
-
|
61
|
-
|
47
|
+
class Comment < ActiveRecord::Base
|
48
|
+
belongs_to :article
|
49
|
+
end
|
62
50
|
|
63
|
-
<
|
64
|
-
|
65
|
-
|
51
|
+
class CommentArchive < ActiveRecord::Base
|
52
|
+
belongs_to :article, :class_name => 'ArticleArchive', :foreign_key => 'article_id'
|
53
|
+
end
|
66
54
|
</pre>
|
67
55
|
|
68
|
-
|
56
|
+
Reserve a spot
|
57
|
+
--------------
|
69
58
|
|
70
|
-
|
71
|
-
-----------------
|
59
|
+
Before you create a record, you can "reserve a spot" on a table that you will move the record to later.
|
72
60
|
|
73
61
|
<pre>
|
74
|
-
|
75
|
-
ArticleArchive.last.move_from
|
62
|
+
ArticleArchive.create(:id => Article.reserve_id)
|
76
63
|
</pre>
|
77
64
|
|
78
|
-
You can access the movable table by prepending its name to the original class name. In this example, you would use <code>ArticleArchive</code>.
|
79
|
-
|
80
|
-
<a name="magic_columns"></a>
|
81
|
-
|
82
65
|
Magic columns
|
83
66
|
-------------
|
84
67
|
|
85
|
-
### move_id
|
86
|
-
|
87
|
-
By default, restoring a record will only restore itself and not its movable relationships.
|
88
|
-
|
89
|
-
To restore the relationships automatically, add the <code>move_id</code> column to all movable tables involved.
|
90
|
-
|
91
68
|
### moved_at
|
92
69
|
|
93
|
-
If
|
94
|
-
|
95
|
-
See the <a href="#create_the_movable_table">create the movable table</a> section for an example of how to add the magic columns.
|
70
|
+
If a table contains the column <code>moved_at</code>, it will automatically be populated with the date and time it was moved.
|
data/lib/mover.rb
CHANGED
@@ -2,68 +2,87 @@ require File.expand_path("#{File.dirname(__FILE__)}/../require")
|
|
2
2
|
Require.lib!
|
3
3
|
|
4
4
|
module Mover
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
base.send :include, Included
|
10
|
-
end
|
5
|
+
def self.included(base)
|
6
|
+
unless base.included_modules.include?(InstanceMethods)
|
7
|
+
base.extend ClassMethods
|
8
|
+
base.send :include, InstanceMethods
|
11
9
|
end
|
10
|
+
end
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
12
|
+
module ClassMethods
|
13
|
+
|
14
|
+
def after_move_to(to_class, &block)
|
15
|
+
@after_move_to ||= []
|
16
|
+
@after_move_to << [ to_class, block ]
|
17
|
+
end
|
18
|
+
|
19
|
+
def before_move_to(to_class, &block)
|
20
|
+
@before_move_to ||= []
|
21
|
+
@before_move_to << [ to_class, block ]
|
22
|
+
end
|
23
|
+
|
24
|
+
def move_to(to_class, conditions, instance=nil)
|
25
|
+
from_class = self
|
26
|
+
# Conditions
|
27
|
+
add_conditions! where = '', conditions
|
28
|
+
# Columns
|
29
|
+
insert = from_class.column_names & to_class.column_names
|
30
|
+
insert -= [ 'moved_at' ]
|
31
|
+
insert.collect! { |col| connection.quote_column_name(col) }
|
32
|
+
select = insert.clone
|
33
|
+
# Magic columns
|
34
|
+
if to_class.column_names.include?('moved_at')
|
35
|
+
insert << connection.quote_column_name('moved_at')
|
36
|
+
select << connection.quote(Time.now.utc)
|
37
|
+
end
|
38
|
+
# Callbacks
|
39
|
+
collector = lambda { |(klass, block)| block if eval(klass.to_s) == to_class }
|
40
|
+
before = (@before_move_to || []).collect(&collector).compact
|
41
|
+
after = (@after_move_to || []).collect(&collector).compact
|
42
|
+
# Instances
|
43
|
+
instances =
|
44
|
+
if instance
|
45
|
+
[ instance ]
|
46
|
+
elsif before.empty? && after.empty?
|
47
|
+
[]
|
48
|
+
else
|
49
|
+
self.find(:all, :conditions => where[5..-1])
|
22
50
|
end
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
include Mover::Base::Record::InstanceMethods
|
28
|
-
|
29
|
-
self.table_name = "#{self.table_name}_#{type}"
|
30
|
-
|
31
|
-
def self.movable_type
|
32
|
-
#{type.inspect}
|
33
|
-
end
|
34
|
-
|
35
|
-
def moved_from_class
|
36
|
-
#{self.name}
|
37
|
-
end
|
38
|
-
end
|
39
|
-
RUBY
|
51
|
+
# Callback executor
|
52
|
+
exec_callbacks = lambda do |callbacks|
|
53
|
+
callbacks.each do |block|
|
54
|
+
instances.each { |instance| instance.instance_eval(&block) }
|
40
55
|
end
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
56
|
+
end
|
57
|
+
# Execute
|
58
|
+
transaction do
|
59
|
+
exec_callbacks.call before
|
60
|
+
connection.execute(<<-SQL)
|
61
|
+
INSERT INTO #{to_class.table_name} (#{insert.join(', ')})
|
62
|
+
SELECT #{select.join(', ')}
|
63
|
+
FROM #{from_class.table_name}
|
64
|
+
#{where}
|
65
|
+
SQL
|
66
|
+
connection.execute("DELETE FROM #{from_class.table_name} #{where}")
|
67
|
+
exec_callbacks.call after
|
45
68
|
end
|
46
69
|
end
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
base.send :include, Included
|
54
|
-
base.class_eval do
|
55
|
-
class <<self
|
56
|
-
alias_method :method_missing_without_mover, :method_missing
|
57
|
-
alias_method :method_missing, :method_missing_with_mover
|
58
|
-
end
|
59
|
-
end
|
70
|
+
|
71
|
+
def reserve_id
|
72
|
+
id = nil
|
73
|
+
transaction do
|
74
|
+
id = connection.insert("INSERT INTO #{self.table_name} () VALUES ()")
|
75
|
+
connection.execute("DELETE FROM #{self.table_name} WHERE id = #{id}") if id
|
60
76
|
end
|
77
|
+
id
|
61
78
|
end
|
62
79
|
end
|
63
80
|
|
64
|
-
module
|
81
|
+
module InstanceMethods
|
82
|
+
def move_to(to_class)
|
83
|
+
self.class.move_to(to_class, "#{self.class.primary_key} = #{id}", self)
|
84
|
+
end
|
65
85
|
end
|
66
86
|
end
|
67
87
|
|
68
|
-
ActiveRecord::Base.send(:include, Mover
|
69
|
-
ActiveRecord::Migration.send(:include, Mover::Migration)
|
88
|
+
ActiveRecord::Base.send(:include, Mover)
|
data/require.rb
CHANGED
@@ -17,17 +17,11 @@ Require do
|
|
17
17
|
name 'mover'
|
18
18
|
homepage "http://github.com/winton/#{name}"
|
19
19
|
summary "Move ActiveRecord records across tables like it ain't no thang"
|
20
|
-
version '0.
|
20
|
+
version '0.2.0'
|
21
21
|
end
|
22
22
|
|
23
23
|
bin { require 'lib/mover' }
|
24
|
-
|
25
|
-
lib do
|
26
|
-
require 'digest/md5'
|
27
|
-
require 'lib/mover/migrator'
|
28
|
-
require 'lib/mover/record'
|
29
|
-
require 'lib/mover/table'
|
30
|
-
end
|
24
|
+
lib {}
|
31
25
|
|
32
26
|
rakefile do
|
33
27
|
gem(:active_wrapper)
|
@@ -44,6 +38,8 @@ Require do
|
|
44
38
|
require 'rails/init'
|
45
39
|
require 'pp'
|
46
40
|
require 'spec/fixtures/article'
|
41
|
+
require 'spec/fixtures/article_archive'
|
47
42
|
require 'spec/fixtures/comment'
|
43
|
+
require 'spec/fixtures/comment_archive'
|
48
44
|
end
|
49
45
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class CreateFixtures < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
[ :articles, :article_archives ].each do |table|
|
4
|
+
create_table table do |t|
|
5
|
+
t.string :title
|
6
|
+
t.string :body
|
7
|
+
t.boolean :read
|
8
|
+
t.datetime :moved_at
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
[ :comments, :comment_archives ].each do |table|
|
13
|
+
create_table table do |t|
|
14
|
+
t.string :title
|
15
|
+
t.string :body
|
16
|
+
t.boolean :read
|
17
|
+
t.integer :article_id
|
18
|
+
t.datetime :moved_at
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.down
|
24
|
+
[ :articles, :article_archives, :comments, :comment_archives ].each do |table|
|
25
|
+
drop_table table
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/spec/fixtures/article.rb
CHANGED
data/spec/fixtures/comment.rb
CHANGED