legacy_migrations 0.2.3 → 0.2.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/README +3 -0
- data/VERSION +5 -1
- data/legacy_migrations.gemspec +5 -4
- data/lib/legacy_migrations/future_storage.rb +5 -0
- data/lib/legacy_migrations/source_iterators.rb +1 -1
- data/lib/legacy_migrations/transformations.rb +18 -0
- data/lib/legacy_migrations.rb +95 -5
- data/spec/db/schema.rb +6 -0
- data/spec/legacy_migrations_spec.rb +3 -3
- data/spec/lib/transformations_spec.rb +16 -0
- data/spec/models.rb +5 -0
- data/spec/spec_helper.rb +1 -1
- metadata +28 -9
data/README
CHANGED
data/VERSION
CHANGED
data/legacy_migrations.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{legacy_migrations}
|
8
|
-
s.version = "0.2.
|
8
|
+
s.version = "0.2.4"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Bernie Telles"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-08-25}
|
13
13
|
s.description = %q{Rails plugin for transferring or updating data between two db structures.}
|
14
14
|
s.email = %q{bernardo.telles@dms.myflorida.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -25,6 +25,7 @@ Gem::Specification.new do |s|
|
|
25
25
|
"install.rb",
|
26
26
|
"legacy_migrations.gemspec",
|
27
27
|
"lib/legacy_migrations.rb",
|
28
|
+
"lib/legacy_migrations/future_storage.rb",
|
28
29
|
"lib/legacy_migrations/row_matchers.rb",
|
29
30
|
"lib/legacy_migrations/source_iterators.rb",
|
30
31
|
"lib/legacy_migrations/squirrel.rb",
|
@@ -46,7 +47,7 @@ Gem::Specification.new do |s|
|
|
46
47
|
s.homepage = %q{http://github.com/btelles/legacy_migrations}
|
47
48
|
s.rdoc_options = ["--charset=UTF-8"]
|
48
49
|
s.require_paths = ["lib"]
|
49
|
-
s.rubygems_version = %q{1.3.
|
50
|
+
s.rubygems_version = %q{1.3.7}
|
50
51
|
s.summary = %q{Rails plugin for transferring or updating data between two db structures.}
|
51
52
|
s.test_files = [
|
52
53
|
"spec/legacy_migrations_spec.rb",
|
@@ -60,7 +61,7 @@ Gem::Specification.new do |s|
|
|
60
61
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
61
62
|
s.specification_version = 3
|
62
63
|
|
63
|
-
if Gem::Version.new(Gem::
|
64
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
64
65
|
s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
|
65
66
|
else
|
66
67
|
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
@@ -69,6 +69,24 @@ module LegacyMigrations
|
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
72
|
+
def stored(stored_attribute, *args)
|
73
|
+
options = args.extract_options!
|
74
|
+
|
75
|
+
if options[:if]
|
76
|
+
if_method = Proc.new {|record| send(options[:if], record)}
|
77
|
+
else
|
78
|
+
if_method = Proc.new {|record| true }
|
79
|
+
end
|
80
|
+
custom_method = Proc.new {|record|
|
81
|
+
if if_method.call(record)
|
82
|
+
FutureStorage.instance[@from_table.to_s][record.id][stored_attribute]
|
83
|
+
else
|
84
|
+
nil
|
85
|
+
end
|
86
|
+
}
|
87
|
+
@columns.merge!({options[:to] => custom_method})
|
88
|
+
end
|
89
|
+
|
72
90
|
private
|
73
91
|
|
74
92
|
def columns_from_options(columns, options)
|
data/lib/legacy_migrations.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
require 'legacy_migrations/transformations'
|
2
|
+
require 'legacy_migrations/future_storage'
|
2
3
|
require 'legacy_migrations/squirrel'
|
4
|
+
require 'legacy_migrations/source_iterators'
|
5
|
+
require 'legacy_migrations/row_matchers'
|
3
6
|
module LegacyMigrations
|
4
7
|
|
5
8
|
# Define a source and destination table to transfer data
|
@@ -11,15 +14,31 @@ module LegacyMigrations
|
|
11
14
|
# This is useful when you're trying to find faulty data in the source
|
12
15
|
# table, and don't want to run the entire dataset.
|
13
16
|
# * <tt>:validate</tt> - Default = true. Use ActiveRecord validations
|
14
|
-
# when saving destination
|
17
|
+
# when saving the destination rows.
|
15
18
|
# * <tt>:source_type</tt> - Default = :active_record. Sets the source
|
16
19
|
# destination type.
|
17
20
|
# Options:
|
18
|
-
# _:
|
21
|
+
# _:active\_record_: Assumes the From option is a class that inherits
|
19
22
|
# from ActiveRecord::Base, then iterates through each record of From
|
20
23
|
# table by using *From*.all.each...
|
21
24
|
# _:other_: Assumes the From option is an iterable 'collection' whose
|
22
|
-
# elements/items can respond to all
|
25
|
+
# elements/items can respond to all source methods speficied in the given block.
|
26
|
+
# * <tt>:store_as</tt> - Stores the generated destination record as a key
|
27
|
+
# that is retrievable in other transformations. Note that for this to work, the
|
28
|
+
# source object must respond to the method <tt>id</tt> which returns
|
29
|
+
# a value that is unique for all rows within the table (usually
|
30
|
+
# this is just a primary key).
|
31
|
+
#
|
32
|
+
# _Example_
|
33
|
+
# <tt>
|
34
|
+
# transfer_from Mammal, :to => Species, :store_as => 'new_animal' do
|
35
|
+
# match_same_name_attributes
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# transfer_from Person, :to => Animal do
|
39
|
+
# stored 'new_animal', :to => :species
|
40
|
+
# end
|
41
|
+
# </tt>
|
23
42
|
#
|
24
43
|
def transfer_from(from_table, *args, &block)
|
25
44
|
|
@@ -36,6 +55,52 @@ module LegacyMigrations
|
|
36
55
|
@status_report
|
37
56
|
end
|
38
57
|
|
58
|
+
# Define a source and destination table with which to update data
|
59
|
+
#
|
60
|
+
# This method accepts all of the same options as <tt>transfer_from</tt>.
|
61
|
+
#
|
62
|
+
# In addition, you'll need to use a series of columns that match data
|
63
|
+
# from the source to the destination. For example, if your source and
|
64
|
+
# destination data have a social security number, then you'd use the
|
65
|
+
# social security number to match records from the two rows. The following
|
66
|
+
# is how you would do that.
|
67
|
+
#
|
68
|
+
# <tt>
|
69
|
+
# update_from SourceTable, :to => DestinationTable do
|
70
|
+
# based_on do
|
71
|
+
# ssn == from.social_security_number
|
72
|
+
# end
|
73
|
+
#
|
74
|
+
# from :last_name, :to => :last_name
|
75
|
+
# end
|
76
|
+
# </tt>
|
77
|
+
#
|
78
|
+
# Note that when using the 'based_on' method, the left-hannd item always
|
79
|
+
# corresponds to a column method on the destination table.
|
80
|
+
#
|
81
|
+
# The methods available in the based_on block correspond to the well-known
|
82
|
+
# squirrel plugin's syntax. Here's a quick review of the possible operators:
|
83
|
+
#
|
84
|
+
# Handles comparisons in the query. This class is analagous to the columns in the database.
|
85
|
+
# When comparing the Condition to a value, the operators are used as follows:
|
86
|
+
# * ==, === : Straight-up Equals. Can also be used as the "IN" operator if the operand is an Array.
|
87
|
+
# Additionally, when the oprand is +nil+, the comparison is correctly generates as "IS NULL"."
|
88
|
+
# * =~ : The LIKE and REGEXP operators. If the operand is a String, it will generate a LIKE
|
89
|
+
# comparison. If it is a Regexp, the REGEXP operator will be used. NOTE: MySQL regular expressions
|
90
|
+
# are NOT the same as Ruby regular expressions. Also NOTE: No wildcards are inserted into the LIKE
|
91
|
+
# comparison, so you may add them where you wish.
|
92
|
+
# * <=> : Performs a BETWEEN comparison, as long as the operand responds to both #first and #last,
|
93
|
+
# which both Ranges and Arrays do.
|
94
|
+
# * > : A simple greater-than comparison.
|
95
|
+
# * >= : Greater-than or equal-to.
|
96
|
+
# * < : A simple less-than comparison.
|
97
|
+
# * <= : Less-than or equal-to.
|
98
|
+
# * contains? : Like =~, except automatically surrounds the operand in %s, which =~ does not do.
|
99
|
+
# * nil? : Works exactly like "column == nil", but in a nicer syntax, which is what Squirrel is all about.
|
100
|
+
#
|
101
|
+
# ==== Options
|
102
|
+
#
|
103
|
+
#
|
39
104
|
def update_from(from_table, *args, &block)
|
40
105
|
|
41
106
|
configure_transfer(from_table, *args) { yield }
|
@@ -59,6 +124,7 @@ module LegacyMigrations
|
|
59
124
|
to_record.save(false)
|
60
125
|
@current_operation.record_update(to_record)
|
61
126
|
end
|
127
|
+
store_as(to_record, from_record)
|
62
128
|
end
|
63
129
|
else
|
64
130
|
new_destination_record(from_record)
|
@@ -68,22 +134,35 @@ module LegacyMigrations
|
|
68
134
|
end
|
69
135
|
|
70
136
|
private
|
71
|
-
|
137
|
+
|
72
138
|
def configure_transfer(from_table, *args, &block)
|
73
139
|
@columns = {}
|
74
140
|
|
75
141
|
@options = {:validate => true}.merge(args.extract_options!)
|
76
142
|
|
143
|
+
|
77
144
|
@from_table = from_table
|
78
145
|
@to_table = @options[:to]
|
146
|
+
|
147
|
+
add_storage_attribute if @options[:store_as].present?
|
148
|
+
|
79
149
|
@status_report = StatusReport.instance
|
80
150
|
|
81
151
|
yield
|
82
152
|
|
83
|
-
@limit = @options[:limit] ? {:limit
|
153
|
+
@limit = @options[:limit] ? {:limit => @options[:limit]} : {}
|
84
154
|
@type = @options[:source_type] ? @options[:source_type] : :active_record
|
85
155
|
end
|
86
156
|
|
157
|
+
def add_storage_attribute
|
158
|
+
symbol_attr = @options[:store_as].to_sym
|
159
|
+
@from_table.first.class.class_eval do
|
160
|
+
define_method(symbol_attr) do
|
161
|
+
FutureStorage.instance[self.class.to_s][self.id][symbol_attr]
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
87
166
|
def new_destination_record(from_record)
|
88
167
|
columns = @columns.inject({}) do |result, attributes|
|
89
168
|
result[attributes[0]]= attributes[1].call(from_record)
|
@@ -97,6 +176,16 @@ module LegacyMigrations
|
|
97
176
|
new_record.save(false)
|
98
177
|
@current_operation.record_insert(new_record)
|
99
178
|
end
|
179
|
+
store_as(new_record, from_record)
|
180
|
+
end
|
181
|
+
|
182
|
+
def store_as(new_record, from_record)
|
183
|
+
if @options[:store_as].present?
|
184
|
+
@future_storage = FutureStorage.instance
|
185
|
+
@future_storage[@from_table.to_s] ||= {}
|
186
|
+
@future_storage[@from_table.to_s][from_record.id] ||= {}
|
187
|
+
@future_storage[@from_table.to_s][from_record.id].merge!({@options[:store_as].to_sym => new_record})
|
188
|
+
end
|
100
189
|
end
|
101
190
|
|
102
191
|
def report_validation_errors(new_record, from_record, type = 'insert')
|
@@ -106,6 +195,7 @@ module LegacyMigrations
|
|
106
195
|
puts @current_operation.add_validation_error(new_record, from_record).pretty_output
|
107
196
|
end
|
108
197
|
end
|
198
|
+
|
109
199
|
end
|
110
200
|
include LegacyMigrations
|
111
201
|
include LegacyMigrations::Transformations
|
data/spec/db/schema.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
create_table :people, :force => true do |t|
|
4
4
|
t.string :name
|
5
5
|
t.string :not_name
|
6
|
+
t.string :city
|
6
7
|
t.integer :age
|
7
8
|
end
|
8
9
|
|
@@ -11,11 +12,16 @@
|
|
11
12
|
t.string :not_name
|
12
13
|
t.integer :age
|
13
14
|
t.string :first_name
|
15
|
+
t.integer :city_id
|
14
16
|
end
|
15
17
|
|
16
18
|
create_table :sex, :force => true do |t|
|
17
19
|
t.string :name
|
18
20
|
end
|
19
21
|
|
22
|
+
create_table :cities, :force => true do |t|
|
23
|
+
t.string :name
|
24
|
+
end
|
25
|
+
|
20
26
|
end
|
21
27
|
|
@@ -27,7 +27,7 @@ describe LegacyMigrations do
|
|
27
27
|
end
|
28
28
|
it "accepts a CSV file" do
|
29
29
|
person = "a simple name,age\nalbert,123"
|
30
|
-
person_csv =
|
30
|
+
person_csv = CSV.parse(person, :headers => :first_row)
|
31
31
|
transfer_from person_csv, :to => Animal, :source_type => :csv do
|
32
32
|
from 'a simple name', :to => :name
|
33
33
|
end
|
@@ -35,7 +35,7 @@ describe LegacyMigrations do
|
|
35
35
|
end
|
36
36
|
it "limits a CSV file" do
|
37
37
|
person = "a simple name,age\nalbert,123\nsmith,54"
|
38
|
-
person_csv =
|
38
|
+
person_csv = CSV.parse(person, :headers => :first_row)
|
39
39
|
transfer_from person_csv, :to => Animal, :source_type => :csv, :limit => 1 do
|
40
40
|
from 'a simple name', :to => :name
|
41
41
|
end
|
@@ -55,7 +55,7 @@ describe LegacyMigrations do
|
|
55
55
|
end
|
56
56
|
it "rewinds a CSV source" do
|
57
57
|
person = "name,age\nalbert,123\nsmith,54"
|
58
|
-
person_csv =
|
58
|
+
person_csv = CSV.parse(person, :headers => :first_row)
|
59
59
|
transfer_from person_csv, :to => Animal, :source_type => :csv do
|
60
60
|
from :name, :to => :name
|
61
61
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper.rb'))
|
2
2
|
|
3
3
|
describe "transformations" do
|
4
|
+
require 'ruby-debug'
|
4
5
|
describe 'from' do
|
5
6
|
it "transfers attributes, given the two names" do
|
6
7
|
Person.create(:name => 'my first name')
|
@@ -64,5 +65,20 @@ describe "transformations" do
|
|
64
65
|
animal.not_name.should == nil
|
65
66
|
end
|
66
67
|
end
|
68
|
+
describe "store_as" do
|
69
|
+
it "stores a given row for future reference by another transfer or update function" do
|
70
|
+
Person.create(:name => 'choose_me', :not_name => 'not_this_one', :city => 'tally')
|
71
|
+
transfer_from Person, :to => City, :store_as => 'my_city' do
|
72
|
+
from :city, :to => :name
|
73
|
+
end
|
74
|
+
transfer_from Person, :to => Animal do
|
75
|
+
match_same_name_attributes
|
76
|
+
stored :my_city, :to => :city
|
77
|
+
end
|
78
|
+
|
79
|
+
animal = Animal.first
|
80
|
+
animal.city.name.should == 'tally'
|
81
|
+
end
|
82
|
+
end
|
67
83
|
end
|
68
84
|
end
|
data/spec/models.rb
CHANGED
@@ -6,9 +6,14 @@ end
|
|
6
6
|
|
7
7
|
class Animal < ActiveRecord::Base
|
8
8
|
validates_format_of :name, :with => /^(\D)*$/, :allow_nil => true
|
9
|
+
belongs_to :city
|
9
10
|
#name
|
10
11
|
#not_name
|
11
12
|
#first_name
|
12
13
|
#age
|
13
14
|
end
|
15
|
+
|
16
|
+
class City < ActiveRecord::Base
|
17
|
+
has_many :animals
|
18
|
+
end
|
14
19
|
require 'legacy_migrations'
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: legacy_migrations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 31
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
- 4
|
10
|
+
version: 0.2.4
|
5
11
|
platform: ruby
|
6
12
|
authors:
|
7
13
|
- Bernie Telles
|
@@ -9,19 +15,25 @@ autorequire:
|
|
9
15
|
bindir: bin
|
10
16
|
cert_chain: []
|
11
17
|
|
12
|
-
date: 2010-
|
18
|
+
date: 2010-08-25 00:00:00 -04:00
|
13
19
|
default_executable:
|
14
20
|
dependencies:
|
15
21
|
- !ruby/object:Gem::Dependency
|
16
22
|
name: rspec
|
17
|
-
|
18
|
-
|
19
|
-
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
20
26
|
requirements:
|
21
27
|
- - ">="
|
22
28
|
- !ruby/object:Gem::Version
|
29
|
+
hash: 13
|
30
|
+
segments:
|
31
|
+
- 1
|
32
|
+
- 2
|
33
|
+
- 9
|
23
34
|
version: 1.2.9
|
24
|
-
|
35
|
+
type: :development
|
36
|
+
version_requirements: *id001
|
25
37
|
description: Rails plugin for transferring or updating data between two db structures.
|
26
38
|
email: bernardo.telles@dms.myflorida.com
|
27
39
|
executables: []
|
@@ -40,6 +52,7 @@ files:
|
|
40
52
|
- install.rb
|
41
53
|
- legacy_migrations.gemspec
|
42
54
|
- lib/legacy_migrations.rb
|
55
|
+
- lib/legacy_migrations/future_storage.rb
|
43
56
|
- lib/legacy_migrations/row_matchers.rb
|
44
57
|
- lib/legacy_migrations/source_iterators.rb
|
45
58
|
- lib/legacy_migrations/squirrel.rb
|
@@ -67,21 +80,27 @@ rdoc_options:
|
|
67
80
|
require_paths:
|
68
81
|
- lib
|
69
82
|
required_ruby_version: !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
70
84
|
requirements:
|
71
85
|
- - ">="
|
72
86
|
- !ruby/object:Gem::Version
|
87
|
+
hash: 3
|
88
|
+
segments:
|
89
|
+
- 0
|
73
90
|
version: "0"
|
74
|
-
version:
|
75
91
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
|
+
none: false
|
76
93
|
requirements:
|
77
94
|
- - ">="
|
78
95
|
- !ruby/object:Gem::Version
|
96
|
+
hash: 3
|
97
|
+
segments:
|
98
|
+
- 0
|
79
99
|
version: "0"
|
80
|
-
version:
|
81
100
|
requirements: []
|
82
101
|
|
83
102
|
rubyforge_project:
|
84
|
-
rubygems_version: 1.3.
|
103
|
+
rubygems_version: 1.3.7
|
85
104
|
signing_key:
|
86
105
|
specification_version: 3
|
87
106
|
summary: Rails plugin for transferring or updating data between two db structures.
|