data_miner 1.1.8 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +61 -36
- data/data_miner.gemspec +6 -5
- data/lib/data_miner/active_record_extensions.rb +0 -7
- data/lib/data_miner/config.rb +1 -7
- data/lib/data_miner/process.rb +2 -0
- data/lib/data_miner/version.rb +1 -1
- data/lib/data_miner.rb +0 -1
- data/test/helper.rb +2 -1
- data/test/support/automobile_variant.rb +2 -2
- data/test/test_old_syntax.rb +299 -286
- metadata +12 -79
- data/lib/data_miner/schema.rb +0 -241
data/README.rdoc
CHANGED
@@ -11,12 +11,7 @@ You define <tt>data_miner</tt> blocks in your ActiveRecord models. For example,
|
|
11
11
|
class Country < ActiveRecord::Base
|
12
12
|
set_primary_key :iso_3166_code
|
13
13
|
|
14
|
-
data_miner do
|
15
|
-
schema do
|
16
|
-
string 'iso_3166_code'
|
17
|
-
string 'name'
|
18
|
-
end
|
19
|
-
|
14
|
+
data_miner do
|
20
15
|
import 'the official ISO country list',
|
21
16
|
:url => 'http://www.iso.org/iso/list-en1-semic-3.txt',
|
22
17
|
:skip => 2,
|
@@ -34,6 +29,36 @@ Now you can run:
|
|
34
29
|
irb(main):001:0> Country.run_data_miner!
|
35
30
|
=> nil
|
36
31
|
|
32
|
+
== Creating tables from scratch (changed in 1.2)
|
33
|
+
|
34
|
+
We recommend using the <tt>create_table</tt> gem (https://github.com/seamusabshere/create_table)
|
35
|
+
|
36
|
+
This replaces the <tt>schema</tt> method that was available before. It didn't make sense for <tt>data_miner</tt> to provide this natively.
|
37
|
+
|
38
|
+
class Car < ActiveRecord::Base
|
39
|
+
|
40
|
+
# THE NEW WAY - depends on create_table gem, which is not required by default
|
41
|
+
# see the process step in the data_miner block where we actually call create_table!
|
42
|
+
create_table do
|
43
|
+
string :make
|
44
|
+
string :model
|
45
|
+
end
|
46
|
+
|
47
|
+
data_miner do
|
48
|
+
# DEPRECATED - see above
|
49
|
+
# schema do
|
50
|
+
# string :make
|
51
|
+
# string :model
|
52
|
+
# end
|
53
|
+
|
54
|
+
process "create the table, adding and removing columns as necessary" do
|
55
|
+
create_table!
|
56
|
+
end
|
57
|
+
|
58
|
+
# [... other data mining steps]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
37
62
|
==Advanced usage
|
38
63
|
|
39
64
|
This is how we linked together (http://data.brighterplanet.com/aircraft) the FAA's list of aircraft with the US Department of Transportations list of aircraft:
|
@@ -44,6 +69,36 @@ This is how we linked together (http://data.brighterplanet.com/aircraft) the FAA
|
|
44
69
|
# table without breaking associations.
|
45
70
|
set_primary_key :icao_code
|
46
71
|
|
72
|
+
# Use the create_table gem to define the database schema in-line.
|
73
|
+
# It will destructively and automatically add/remove columns.
|
74
|
+
# This is "OK" because you can always just re-run the import script to get the data back.
|
75
|
+
# PS. If you're using DataMapper, you don't need this
|
76
|
+
create_table do
|
77
|
+
string 'icao_code'
|
78
|
+
string 'manufacturer_name'
|
79
|
+
string 'name'
|
80
|
+
string 'bts_name'
|
81
|
+
string 'bts_aircraft_type_code'
|
82
|
+
string 'brighter_planet_aircraft_class_code'
|
83
|
+
string 'fuel_use_aircraft_name'
|
84
|
+
float 'm3'
|
85
|
+
string 'm3_units'
|
86
|
+
float 'm2'
|
87
|
+
string 'm2_units'
|
88
|
+
float 'm1'
|
89
|
+
string 'm1_units'
|
90
|
+
float 'endpoint_fuel'
|
91
|
+
string 'endpoint_fuel_units'
|
92
|
+
float 'seats'
|
93
|
+
float 'distance'
|
94
|
+
string 'distance_units'
|
95
|
+
float 'load_factor'
|
96
|
+
float 'freight_share'
|
97
|
+
float 'payload'
|
98
|
+
float 'weighting'
|
99
|
+
index 'bts_aircraft_type_code'
|
100
|
+
end
|
101
|
+
|
47
102
|
# A dictionary between BTS aircraft type codes and ICAO aircraft
|
48
103
|
# codes that uses string similarity instead of exact matching.
|
49
104
|
# This is preferable to typing everything out.
|
@@ -154,36 +209,6 @@ This is how we linked together (http://data.brighterplanet.com/aircraft) the FAA
|
|
154
209
|
raise DataMiner::Skip unless DataMiner::Run.allowed? Aircraft
|
155
210
|
end
|
156
211
|
|
157
|
-
# Define the database schema in-line.
|
158
|
-
# It will destructively and automatically add/remove columns.
|
159
|
-
# This is "OK" because you can always just re-run the import script to get the data back.
|
160
|
-
# PS. if we were using DataMapper, we wouldn't need this.
|
161
|
-
schema :options => 'ENGINE=InnoDB default charset=utf8' do
|
162
|
-
string 'icao_code'
|
163
|
-
string 'manufacturer_name'
|
164
|
-
string 'name'
|
165
|
-
string 'bts_name'
|
166
|
-
string 'bts_aircraft_type_code'
|
167
|
-
string 'brighter_planet_aircraft_class_code'
|
168
|
-
string 'fuel_use_aircraft_name'
|
169
|
-
float 'm3'
|
170
|
-
string 'm3_units'
|
171
|
-
float 'm2'
|
172
|
-
string 'm2_units'
|
173
|
-
float 'm1'
|
174
|
-
string 'm1_units'
|
175
|
-
float 'endpoint_fuel'
|
176
|
-
string 'endpoint_fuel_units'
|
177
|
-
float 'seats'
|
178
|
-
float 'distance'
|
179
|
-
string 'distance_units'
|
180
|
-
float 'load_factor'
|
181
|
-
float 'freight_share'
|
182
|
-
float 'payload'
|
183
|
-
float 'weighting'
|
184
|
-
index 'bts_aircraft_type_code'
|
185
|
-
end
|
186
|
-
|
187
212
|
# The FAA publishes a document to help people identify aircraft by different names.
|
188
213
|
('A'..'Z').each do |letter|
|
189
214
|
import( "ICAO aircraft codes starting with the letter #{letter} used by the FAA",
|
data/data_miner.gemspec
CHANGED
@@ -27,13 +27,14 @@ Gem::Specification.new do |s|
|
|
27
27
|
s.add_dependency 'blockenspiel', '>=0.3.2'
|
28
28
|
s.add_dependency 'taps', '>=0.3.11'
|
29
29
|
s.add_dependency 'errata', '>=1.0.1'
|
30
|
+
s.add_development_dependency 'create_table', '>=0.0.2'
|
30
31
|
s.add_development_dependency 'loose_tight_dictionary', ">=0.0.5"
|
31
32
|
s.add_development_dependency 'test-unit'
|
32
33
|
s.add_development_dependency 'shoulda'
|
33
34
|
s.add_development_dependency 'mysql'
|
34
|
-
if RUBY_VERSION >= '1.9'
|
35
|
-
|
36
|
-
else
|
37
|
-
|
38
|
-
end
|
35
|
+
# if RUBY_VERSION >= '1.9'
|
36
|
+
# s.add_development_dependency 'ruby-debug19'
|
37
|
+
# else
|
38
|
+
# s.add_development_dependency 'ruby-debug'
|
39
|
+
# end
|
39
40
|
end
|
@@ -6,8 +6,6 @@ class DataMiner
|
|
6
6
|
def data_miner(options = {}, &blk)
|
7
7
|
::DataMiner.instance.start_logging
|
8
8
|
|
9
|
-
::DataMiner.logger.debug "Database table `#{table_name}` doesn't exist. It might be created in the data_miner block, but if it's not, DataMiner probably won't work properly until you run a migration or otherwise fix the schema." unless table_exists?
|
10
|
-
|
11
9
|
::DataMiner.instance.resource_names.push self.name unless ::DataMiner.instance.resource_names.include? self.name
|
12
10
|
|
13
11
|
# this is class_eval'ed here so that each ActiveRecord descendant has its own copy, or none at all
|
@@ -19,11 +17,6 @@ class DataMiner
|
|
19
17
|
def self.run_data_miner!(options = {})
|
20
18
|
data_miner_config.run options
|
21
19
|
end
|
22
|
-
def self.execute_schema
|
23
|
-
if schema = data_miner_config.steps.detect { |s| s.instance_of?(::DataMiner::Schema) }
|
24
|
-
schema.run
|
25
|
-
end
|
26
|
-
end
|
27
20
|
end
|
28
21
|
|
29
22
|
if options[:append]
|
data/lib/data_miner/config.rb
CHANGED
@@ -18,13 +18,7 @@ class DataMiner
|
|
18
18
|
# def attributes
|
19
19
|
# @attributes ||= {}
|
20
20
|
# end
|
21
|
-
|
22
|
-
def schema(create_table_options = {}, &blk)
|
23
|
-
step = Schema.new self, create_table_options
|
24
|
-
::Blockenspiel.invoke blk, step
|
25
|
-
steps.push step
|
26
|
-
end
|
27
|
-
|
21
|
+
|
28
22
|
def process(method_id_or_block_description, &blk)
|
29
23
|
step = Process.new self, method_id_or_block_description, &blk
|
30
24
|
steps.push step
|
data/lib/data_miner/process.rb
CHANGED
data/lib/data_miner/version.rb
CHANGED
data/lib/data_miner.rb
CHANGED
data/test/helper.rb
CHANGED
@@ -3,7 +3,8 @@ require 'bundler'
|
|
3
3
|
Bundler.setup
|
4
4
|
require 'test/unit'
|
5
5
|
require 'shoulda'
|
6
|
-
require '
|
6
|
+
require 'create_table'
|
7
|
+
# require 'ruby-debug'
|
7
8
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
8
9
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
9
10
|
require 'data_miner'
|
@@ -42,8 +42,8 @@ class AutomobileVariant < ActiveRecord::Base
|
|
42
42
|
}
|
43
43
|
|
44
44
|
class ParserB
|
45
|
-
require '
|
46
|
-
::
|
45
|
+
require 'fixed_width'
|
46
|
+
::FixedWidth.define :fuel_economy_guide_b do |d|
|
47
47
|
d.rows do |row|
|
48
48
|
row.trap { true } # there's only one section
|
49
49
|
row.column 'active_year' , 4, :type => :integer # ACTIVE YEAR
|
data/test/test_old_syntax.rb
CHANGED
@@ -567,18 +567,22 @@ end
|
|
567
567
|
class AutomobileMakeFleetYear < ActiveRecord::Base
|
568
568
|
set_primary_key :name
|
569
569
|
|
570
|
+
create_table do
|
571
|
+
string "name"
|
572
|
+
string "make_name"
|
573
|
+
string "fleet"
|
574
|
+
integer "year"
|
575
|
+
float "fuel_efficiency"
|
576
|
+
string "fuel_efficiency_units"
|
577
|
+
integer "volume"
|
578
|
+
string "make_year_name"
|
579
|
+
datetime "created_at"
|
580
|
+
datetime "updated_at"
|
581
|
+
end
|
582
|
+
|
570
583
|
data_miner do
|
571
|
-
|
572
|
-
|
573
|
-
string "make_name"
|
574
|
-
string "fleet"
|
575
|
-
integer "year"
|
576
|
-
float "fuel_efficiency"
|
577
|
-
string "fuel_efficiency_units"
|
578
|
-
integer "volume"
|
579
|
-
string "make_year_name"
|
580
|
-
datetime "created_at"
|
581
|
-
datetime "updated_at"
|
584
|
+
process "create table" do
|
585
|
+
create_table!
|
582
586
|
end
|
583
587
|
|
584
588
|
process "finish if i tell you to" do
|
@@ -605,298 +609,307 @@ end
|
|
605
609
|
|
606
610
|
class CensusDivisionTrois < ActiveRecord::Base
|
607
611
|
set_primary_key :number_code
|
612
|
+
|
613
|
+
create_table do
|
614
|
+
string 'number_code'
|
615
|
+
string 'name'
|
616
|
+
string 'census_region_name'
|
617
|
+
integer 'census_region_number'
|
618
|
+
index 'census_region_name', :name => 'homefry'
|
619
|
+
index ['number_code', 'name', 'census_region_name', 'census_region_number']
|
620
|
+
end
|
621
|
+
|
608
622
|
data_miner do
|
609
|
-
|
610
|
-
|
611
|
-
string 'name'
|
612
|
-
string 'census_region_name'
|
613
|
-
integer 'census_region_number'
|
614
|
-
index 'census_region_name', :name => 'homefry'
|
615
|
-
index ['number_code', 'name', 'census_region_name', 'census_region_number']
|
623
|
+
process "create table" do
|
624
|
+
create_table!
|
616
625
|
end
|
617
626
|
end
|
618
627
|
end
|
619
628
|
|
620
629
|
class CensusDivisionFour < ActiveRecord::Base
|
630
|
+
create_table do
|
631
|
+
string 'number_code'
|
632
|
+
string 'name'
|
633
|
+
string 'census_region_name'
|
634
|
+
integer 'census_region_number'
|
635
|
+
index 'census_region_name', :name => 'homefry'
|
636
|
+
end
|
637
|
+
|
621
638
|
data_miner do
|
622
|
-
|
623
|
-
|
624
|
-
string 'name'
|
625
|
-
string 'census_region_name'
|
626
|
-
integer 'census_region_number'
|
627
|
-
index 'census_region_name', :name => 'homefry'
|
639
|
+
process "create table" do
|
640
|
+
create_table!
|
628
641
|
end
|
629
642
|
end
|
630
643
|
end
|
631
644
|
|
632
645
|
# todo: have somebody properly organize these
|
633
646
|
class TestOldSyntax < Test::Unit::TestCase
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
647
|
+
if ENV['WIP']
|
648
|
+
context 'with nullify option' do
|
649
|
+
should 'treat blank fields as null values' do
|
650
|
+
Aircraft.delete_all
|
651
|
+
Aircraft.data_miner_runs.delete_all
|
652
|
+
Aircraft.run_data_miner!
|
653
|
+
assert_greater_than 0, Aircraft.count
|
654
|
+
assert_false Aircraft.where(:brighter_planet_aircraft_class_code => nil).empty?
|
655
|
+
end
|
656
|
+
end
|
657
|
+
end
|
658
|
+
|
659
|
+
if ENV['ALL'] == 'true'
|
660
|
+
should 'directly create a table for the model' do
|
661
|
+
if AutomobileMakeFleetYear.table_exists?
|
662
|
+
ActiveRecord::Base.connection.execute 'DROP TABLE automobile_make_fleet_years;'
|
663
|
+
end
|
664
|
+
AutomobileMakeFleetYear.create_table!
|
665
|
+
assert AutomobileMakeFleetYear.table_exists?
|
666
|
+
end
|
667
|
+
end
|
668
|
+
|
669
|
+
if ENV['ALL'] == 'true' or ENV['FAST'] == 'true'
|
670
|
+
should 'append to an existing config' do
|
671
|
+
AutomobileFuelType.class_eval do
|
672
|
+
data_miner :append => true do
|
673
|
+
import 'example1', :url => 'http://example1.com' do
|
674
|
+
key 'code'
|
675
|
+
store 'name'
|
676
|
+
end
|
677
|
+
end
|
678
|
+
data_miner :append => true do
|
679
|
+
import 'example2', :url => 'http://example2.com' do
|
680
|
+
key 'code'
|
681
|
+
store 'name'
|
682
|
+
end
|
683
|
+
end
|
684
|
+
end
|
685
|
+
assert_equal 'http://example1.com', AutomobileFuelType.data_miner_config.steps[-2].table.url
|
686
|
+
assert_equal 'http://example2.com', AutomobileFuelType.data_miner_config.steps[-1].table.url
|
687
|
+
end
|
688
|
+
|
689
|
+
should 'override an existing data_miner configuration' do
|
690
|
+
AutomobileFuelType.class_eval do
|
691
|
+
data_miner do
|
692
|
+
import 'example', :url => 'http://example.com' do
|
693
|
+
key 'code'
|
694
|
+
store 'name'
|
695
|
+
end
|
696
|
+
end
|
697
|
+
end
|
698
|
+
assert_kind_of DataMiner::Import, AutomobileFuelType.data_miner_config.steps.first
|
699
|
+
assert_equal 'http://example.com', AutomobileFuelType.data_miner_config.steps.first.table.url
|
700
|
+
end
|
701
|
+
should "stop and finish if it gets a DataMiner::Finish" do
|
702
|
+
AutomobileMakeFleetYear.delete_all
|
703
|
+
AutomobileMakeFleetYear.data_miner_runs.delete_all
|
704
|
+
$force_finish = true
|
705
|
+
AutomobileMakeFleetYear.run_data_miner!
|
706
|
+
assert_equal 0, AutomobileMakeFleetYear.count
|
707
|
+
assert (AutomobileMakeFleetYear.data_miner_runs.count > 0)
|
708
|
+
assert AutomobileMakeFleetYear.data_miner_runs.all? { |run| run.finished? and not run.skipped and not run.killed? }
|
709
|
+
$force_finish = false
|
710
|
+
AutomobileMakeFleetYear.run_data_miner!
|
711
|
+
assert AutomobileMakeFleetYear.exists?(:name => 'Alfa Romeo IP 1978')
|
712
|
+
end
|
713
|
+
|
714
|
+
should "stop and register skipped if it gets a DataMiner::Skip" do
|
715
|
+
AutomobileMakeFleetYear.delete_all
|
716
|
+
AutomobileMakeFleetYear.data_miner_runs.delete_all
|
717
|
+
$force_skip = true
|
718
|
+
AutomobileMakeFleetYear.run_data_miner!
|
719
|
+
assert_equal 0, AutomobileMakeFleetYear.count
|
720
|
+
assert (AutomobileMakeFleetYear.data_miner_runs.count > 0)
|
721
|
+
assert AutomobileMakeFleetYear.data_miner_runs.all? { |run| run.skipped? and not run.finished? and not run.killed? }
|
722
|
+
$force_skip = false
|
723
|
+
AutomobileMakeFleetYear.run_data_miner!
|
724
|
+
assert AutomobileMakeFleetYear.exists?(:name => 'Alfa Romeo IP 1978')
|
725
|
+
end
|
726
|
+
|
727
|
+
should "eagerly enforce a schema" do
|
728
|
+
ActiveRecord::Base.connection.create_table 'census_division_trois', :force => true, :options => 'ENGINE=InnoDB default charset=utf8' do |t|
|
729
|
+
t.string 'name'
|
730
|
+
t.string 'census_region_name'
|
731
|
+
# t.integer 'census_region_number'
|
732
|
+
end
|
733
|
+
ActiveRecord::Base.connection.execute 'ALTER TABLE census_division_trois ADD INDEX (census_region_name)'
|
734
|
+
CensusDivisionTrois.reset_column_information
|
735
|
+
missing_columns = %w{ census_region_number }
|
736
|
+
|
737
|
+
# sanity check
|
738
|
+
missing_columns.each do |column|
|
739
|
+
assert_false CensusDivisionTrois.column_names.include?(column)
|
740
|
+
end
|
741
|
+
assert_false ActiveRecord::Base.connection.indexes(CensusDivisionTrois.table_name).any? { |index| index.name == 'homefry' }
|
742
|
+
|
743
|
+
3.times do
|
744
|
+
CensusDivisionTrois.run_data_miner!
|
745
|
+
missing_columns.each do |column|
|
746
|
+
assert CensusDivisionTrois.column_names.include?(column)
|
747
|
+
end
|
748
|
+
assert ActiveRecord::Base.connection.indexes(CensusDivisionTrois.table_name).any? { |index| index.name == 'homefry' }
|
749
|
+
assert_equal :string, CensusDivisionTrois.columns_hash[CensusDivisionTrois.primary_key].type
|
750
|
+
end
|
751
|
+
end
|
752
|
+
|
753
|
+
should "let schemas work with default id primary keys" do
|
754
|
+
ActiveRecord::Base.connection.create_table 'census_division_fours', :force => true, :options => 'ENGINE=InnoDB default charset=utf8' do |t|
|
755
|
+
t.string 'name'
|
756
|
+
t.string 'census_region_name'
|
757
|
+
# t.integer 'census_region_number'
|
758
|
+
end
|
759
|
+
ActiveRecord::Base.connection.execute 'ALTER TABLE census_division_fours ADD INDEX (census_region_name)'
|
760
|
+
CensusDivisionFour.reset_column_information
|
761
|
+
missing_columns = %w{ census_region_number }
|
762
|
+
|
763
|
+
# sanity check
|
764
|
+
missing_columns.each do |column|
|
765
|
+
assert_false CensusDivisionFour.column_names.include?(column)
|
766
|
+
end
|
767
|
+
assert_false ActiveRecord::Base.connection.indexes(CensusDivisionFour.table_name).any? { |index| index.name == 'homefry' }
|
768
|
+
|
769
|
+
3.times do
|
770
|
+
CensusDivisionFour.run_data_miner!
|
771
|
+
missing_columns.each do |column|
|
772
|
+
assert CensusDivisionFour.column_names.include?(column)
|
773
|
+
end
|
774
|
+
assert ActiveRecord::Base.connection.indexes(CensusDivisionFour.table_name).any? { |index| index.name == 'homefry' }
|
775
|
+
assert_equal :integer, CensusDivisionFour.columns_hash[CensusDivisionFour.primary_key].type
|
776
|
+
end
|
777
|
+
end
|
765
778
|
|
766
779
|
should "allow specifying dictionaries explicitly" do
|
767
780
|
CensusDivisionDeux.run_data_miner!
|
768
781
|
assert_equal 'South Region', CensusDivisionDeux.find(5).census_region_name
|
769
782
|
end
|
770
783
|
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
784
|
+
should "be able to key on things other than the primary key" do
|
785
|
+
Aircraft.run_data_miner!
|
786
|
+
assert_equal 'SP', Aircraft.find('DHC6').brighter_planet_aircraft_class_code
|
787
|
+
end
|
788
|
+
|
789
|
+
should "be able to synthesize rows without using a full parser class" do
|
790
|
+
AutomobileMakeFleetYear.run_data_miner!
|
791
|
+
assert AutomobileMakeFleetYear.exists?(:name => 'Alfa Romeo IP 1978')
|
792
|
+
end
|
793
|
+
|
794
|
+
should "keep a call stack so that you can call run_data_miner! on a child" do
|
795
|
+
CrosscallingCensusDivision.run_data_miner!
|
796
|
+
assert CrosscallingCensusDivision.exists? :name => 'Mountain Division', :number => 8, :census_region_number => 4, :census_region_name => 'West Region'
|
797
|
+
assert CrosscallingCensusRegion.exists? :name => 'West Region', :number => 4
|
798
|
+
end
|
799
|
+
|
800
|
+
should "keep a call stack so that you can call run_data_miner! on a parent" do
|
801
|
+
CrosscallingCensusRegion.run_data_miner!
|
802
|
+
assert CrosscallingCensusDivision.exists? :name => 'Mountain Division', :number => 8, :census_region_number => 4, :census_region_name => 'West Region'
|
803
|
+
assert CrosscallingCensusRegion.exists? :name => 'West Region', :number => 4
|
804
|
+
end
|
805
|
+
|
806
|
+
should "import airports" do
|
807
|
+
Airport.run_data_miner!
|
808
|
+
assert Airport.count > 0
|
809
|
+
end
|
810
|
+
|
811
|
+
should "tap airports" do
|
812
|
+
TappedAirport.run_data_miner!
|
813
|
+
assert TappedAirport.count > 0
|
814
|
+
end
|
815
|
+
|
816
|
+
should "pull in census divisions using a data.brighterplanet.com dictionary" do
|
817
|
+
CensusDivision.run_data_miner!
|
818
|
+
assert CensusDivision.count > 0
|
819
|
+
end
|
820
|
+
|
821
|
+
should "have a way to queue up runs that works with delated_job's send_later" do
|
822
|
+
assert AutomobileVariant.respond_to?(:run_data_miner!)
|
823
|
+
end
|
824
|
+
|
825
|
+
should "be idempotent" do
|
826
|
+
Country.data_miner_config.run
|
827
|
+
a = Country.count
|
828
|
+
Country.data_miner_config.run
|
829
|
+
b = Country.count
|
830
|
+
assert_equal a, b
|
831
|
+
|
832
|
+
CensusRegion.data_miner_config.run
|
833
|
+
a = CensusRegion.count
|
834
|
+
CensusRegion.data_miner_config.run
|
835
|
+
b = CensusRegion.count
|
836
|
+
assert_equal a, b
|
837
|
+
end
|
838
|
+
|
839
|
+
should "hash things" do
|
840
|
+
AutomobileVariant.data_miner_config.steps[0].run
|
841
|
+
assert AutomobileVariant.first.row_hash.present?
|
842
|
+
end
|
843
|
+
|
844
|
+
should "process a callback block instead of a method" do
|
845
|
+
AutomobileVariant.delete_all
|
846
|
+
AutomobileVariant.data_miner_config.steps[0].run
|
847
|
+
assert !AutomobileVariant.first.fuel_efficiency_city.present?
|
848
|
+
AutomobileVariant.data_miner_config.steps.last.run
|
849
|
+
assert AutomobileVariant.first.fuel_efficiency_city.present?
|
850
|
+
end
|
851
|
+
|
852
|
+
should "keep a log when it does a run" do
|
853
|
+
approx_started_at = Time.now
|
854
|
+
DataMiner.run :resource_names => %w{ Country }
|
855
|
+
approx_terminated_at = Time.now
|
856
|
+
last_run = DataMiner::Run.first(:conditions => { :resource_name => 'Country' }, :order => 'id DESC')
|
857
|
+
assert (last_run.started_at - approx_started_at).abs < 5 # seconds
|
858
|
+
assert (last_run.terminated_at - approx_terminated_at).abs < 5 # seconds
|
859
|
+
end
|
860
|
+
|
861
|
+
should "request a re-import from scratch" do
|
862
|
+
c = Country.new
|
863
|
+
c.iso_3166 = 'JUNK'
|
864
|
+
c.save!
|
865
|
+
assert Country.exists?(:iso_3166 => 'JUNK')
|
866
|
+
DataMiner.run :resource_names => %w{ Country }, :from_scratch => true
|
867
|
+
assert !Country.exists?(:iso_3166 => 'JUNK')
|
868
|
+
end
|
869
|
+
|
870
|
+
should "know what runs were on a resource" do
|
871
|
+
DataMiner.run :resource_names => %w{ Country }
|
872
|
+
DataMiner.run :resource_names => %w{ Country }
|
873
|
+
assert Country.data_miner_runs.count > 0
|
874
|
+
end
|
875
|
+
end
|
876
|
+
|
877
|
+
if ENV['ALL'] == 'true' or ENV['SLOW'] == 'true'
|
878
|
+
should "allow errata to be specified with a shorthand, assuming the responder is the resource class itself" do
|
879
|
+
AircraftDeux.run_data_miner!
|
880
|
+
assert AircraftDeux.exists? :icao_code => 'DC91', :bts_aircraft_type_code => '630'
|
881
|
+
end
|
882
|
+
|
883
|
+
should "mine aircraft" do
|
884
|
+
Aircraft.run_data_miner!
|
885
|
+
assert Aircraft.exists? :icao_code => 'DC91', :bts_aircraft_type_code => '630'
|
886
|
+
end
|
887
|
+
|
888
|
+
should "mine automobile variants" do
|
889
|
+
AutomobileVariant.run_data_miner!
|
890
|
+
assert AutomobileVariant.count('make_name LIKE "%tesla"') > 0
|
891
|
+
end
|
892
|
+
|
893
|
+
should "mine T100 flight segments" do
|
894
|
+
T100FlightSegment.run_data_miner!
|
895
|
+
assert T100FlightSegment.count('dest_country_name LIKE "%United States"') > 0
|
896
|
+
end
|
897
|
+
|
898
|
+
should "mine residence survey responses" do
|
899
|
+
ResidentialEnergyConsumptionSurveyResponse.run_data_miner!
|
900
|
+
assert ResidentialEnergyConsumptionSurveyResponse.find(6).residence_class.start_with?('Single-family detached house')
|
901
|
+
end
|
902
|
+
end
|
903
|
+
should "mark the run as skipped if verification fails" do
|
904
|
+
AutomobileFuelType.data_miner_config.instance_eval do
|
905
|
+
verify "failure" do
|
906
|
+
false
|
907
|
+
end
|
908
|
+
end
|
909
|
+
|
910
|
+
DataMiner::Run.delete_all
|
911
|
+
assert_raise do
|
912
|
+
AutomobileFuelType.run_data_miner! :from_scratch => true
|
913
|
+
end
|
914
|
+
end
|
902
915
|
end
|
metadata
CHANGED
@@ -1,13 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: data_miner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash: 3
|
5
4
|
prerelease:
|
6
|
-
|
7
|
-
- 1
|
8
|
-
- 1
|
9
|
-
- 8
|
10
|
-
version: 1.1.8
|
5
|
+
version: 1.2.0
|
11
6
|
platform: ruby
|
12
7
|
authors:
|
13
8
|
- Seamus Abshere
|
@@ -17,7 +12,8 @@ autorequire:
|
|
17
12
|
bindir: bin
|
18
13
|
cert_chain: []
|
19
14
|
|
20
|
-
date: 2011-
|
15
|
+
date: 2011-06-06 00:00:00 -05:00
|
16
|
+
default_executable:
|
21
17
|
dependencies:
|
22
18
|
- !ruby/object:Gem::Dependency
|
23
19
|
name: remote_table
|
@@ -27,11 +23,6 @@ dependencies:
|
|
27
23
|
requirements:
|
28
24
|
- - ">="
|
29
25
|
- !ruby/object:Gem::Version
|
30
|
-
hash: 27
|
31
|
-
segments:
|
32
|
-
- 1
|
33
|
-
- 2
|
34
|
-
- 2
|
35
26
|
version: 1.2.2
|
36
27
|
type: :runtime
|
37
28
|
version_requirements: *id001
|
@@ -43,11 +34,6 @@ dependencies:
|
|
43
34
|
requirements:
|
44
35
|
- - ">="
|
45
36
|
- !ruby/object:Gem::Version
|
46
|
-
hash: 23
|
47
|
-
segments:
|
48
|
-
- 0
|
49
|
-
- 0
|
50
|
-
- 4
|
51
37
|
version: 0.0.4
|
52
38
|
type: :runtime
|
53
39
|
version_requirements: *id002
|
@@ -59,11 +45,6 @@ dependencies:
|
|
59
45
|
requirements:
|
60
46
|
- - ">="
|
61
47
|
- !ruby/object:Gem::Version
|
62
|
-
hash: 11
|
63
|
-
segments:
|
64
|
-
- 2
|
65
|
-
- 3
|
66
|
-
- 4
|
67
48
|
version: 2.3.4
|
68
49
|
type: :runtime
|
69
50
|
version_requirements: *id003
|
@@ -75,11 +56,6 @@ dependencies:
|
|
75
56
|
requirements:
|
76
57
|
- - ">="
|
77
58
|
- !ruby/object:Gem::Version
|
78
|
-
hash: 11
|
79
|
-
segments:
|
80
|
-
- 2
|
81
|
-
- 3
|
82
|
-
- 4
|
83
59
|
version: 2.3.4
|
84
60
|
type: :runtime
|
85
61
|
version_requirements: *id004
|
@@ -91,11 +67,6 @@ dependencies:
|
|
91
67
|
requirements:
|
92
68
|
- - ">="
|
93
69
|
- !ruby/object:Gem::Version
|
94
|
-
hash: 15
|
95
|
-
segments:
|
96
|
-
- 1
|
97
|
-
- 4
|
98
|
-
- 4
|
99
70
|
version: 1.4.4
|
100
71
|
type: :runtime
|
101
72
|
version_requirements: *id005
|
@@ -107,11 +78,6 @@ dependencies:
|
|
107
78
|
requirements:
|
108
79
|
- - ">="
|
109
80
|
- !ruby/object:Gem::Version
|
110
|
-
hash: 23
|
111
|
-
segments:
|
112
|
-
- 0
|
113
|
-
- 3
|
114
|
-
- 2
|
115
81
|
version: 0.3.2
|
116
82
|
type: :runtime
|
117
83
|
version_requirements: *id006
|
@@ -123,11 +89,6 @@ dependencies:
|
|
123
89
|
requirements:
|
124
90
|
- - ">="
|
125
91
|
- !ruby/object:Gem::Version
|
126
|
-
hash: 5
|
127
|
-
segments:
|
128
|
-
- 0
|
129
|
-
- 3
|
130
|
-
- 11
|
131
92
|
version: 0.3.11
|
132
93
|
type: :runtime
|
133
94
|
version_requirements: *id007
|
@@ -139,83 +100,61 @@ dependencies:
|
|
139
100
|
requirements:
|
140
101
|
- - ">="
|
141
102
|
- !ruby/object:Gem::Version
|
142
|
-
hash: 21
|
143
|
-
segments:
|
144
|
-
- 1
|
145
|
-
- 0
|
146
|
-
- 1
|
147
103
|
version: 1.0.1
|
148
104
|
type: :runtime
|
149
105
|
version_requirements: *id008
|
150
106
|
- !ruby/object:Gem::Dependency
|
151
|
-
name:
|
107
|
+
name: create_table
|
152
108
|
prerelease: false
|
153
109
|
requirement: &id009 !ruby/object:Gem::Requirement
|
154
110
|
none: false
|
155
111
|
requirements:
|
156
112
|
- - ">="
|
157
113
|
- !ruby/object:Gem::Version
|
158
|
-
|
159
|
-
segments:
|
160
|
-
- 0
|
161
|
-
- 0
|
162
|
-
- 5
|
163
|
-
version: 0.0.5
|
114
|
+
version: 0.0.2
|
164
115
|
type: :development
|
165
116
|
version_requirements: *id009
|
166
117
|
- !ruby/object:Gem::Dependency
|
167
|
-
name:
|
118
|
+
name: loose_tight_dictionary
|
168
119
|
prerelease: false
|
169
120
|
requirement: &id010 !ruby/object:Gem::Requirement
|
170
121
|
none: false
|
171
122
|
requirements:
|
172
123
|
- - ">="
|
173
124
|
- !ruby/object:Gem::Version
|
174
|
-
|
175
|
-
segments:
|
176
|
-
- 0
|
177
|
-
version: "0"
|
125
|
+
version: 0.0.5
|
178
126
|
type: :development
|
179
127
|
version_requirements: *id010
|
180
128
|
- !ruby/object:Gem::Dependency
|
181
|
-
name:
|
129
|
+
name: test-unit
|
182
130
|
prerelease: false
|
183
131
|
requirement: &id011 !ruby/object:Gem::Requirement
|
184
132
|
none: false
|
185
133
|
requirements:
|
186
134
|
- - ">="
|
187
135
|
- !ruby/object:Gem::Version
|
188
|
-
hash: 3
|
189
|
-
segments:
|
190
|
-
- 0
|
191
136
|
version: "0"
|
192
137
|
type: :development
|
193
138
|
version_requirements: *id011
|
194
139
|
- !ruby/object:Gem::Dependency
|
195
|
-
name:
|
140
|
+
name: shoulda
|
196
141
|
prerelease: false
|
197
142
|
requirement: &id012 !ruby/object:Gem::Requirement
|
198
143
|
none: false
|
199
144
|
requirements:
|
200
145
|
- - ">="
|
201
146
|
- !ruby/object:Gem::Version
|
202
|
-
hash: 3
|
203
|
-
segments:
|
204
|
-
- 0
|
205
147
|
version: "0"
|
206
148
|
type: :development
|
207
149
|
version_requirements: *id012
|
208
150
|
- !ruby/object:Gem::Dependency
|
209
|
-
name:
|
151
|
+
name: mysql
|
210
152
|
prerelease: false
|
211
153
|
requirement: &id013 !ruby/object:Gem::Requirement
|
212
154
|
none: false
|
213
155
|
requirements:
|
214
156
|
- - ">="
|
215
157
|
- !ruby/object:Gem::Version
|
216
|
-
hash: 3
|
217
|
-
segments:
|
218
|
-
- 0
|
219
158
|
version: "0"
|
220
159
|
type: :development
|
221
160
|
version_requirements: *id013
|
@@ -245,7 +184,6 @@ files:
|
|
245
184
|
- lib/data_miner/import.rb
|
246
185
|
- lib/data_miner/process.rb
|
247
186
|
- lib/data_miner/run.rb
|
248
|
-
- lib/data_miner/schema.rb
|
249
187
|
- lib/data_miner/tap.rb
|
250
188
|
- lib/data_miner/verify.rb
|
251
189
|
- lib/data_miner/version.rb
|
@@ -260,6 +198,7 @@ files:
|
|
260
198
|
- test/test_data_miner_process.rb
|
261
199
|
- test/test_data_miner_verify.rb
|
262
200
|
- test/test_old_syntax.rb
|
201
|
+
has_rdoc: true
|
263
202
|
homepage: https://github.com/seamusabshere/data_miner
|
264
203
|
licenses: []
|
265
204
|
|
@@ -273,23 +212,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
273
212
|
requirements:
|
274
213
|
- - ">="
|
275
214
|
- !ruby/object:Gem::Version
|
276
|
-
hash: 3
|
277
|
-
segments:
|
278
|
-
- 0
|
279
215
|
version: "0"
|
280
216
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
281
217
|
none: false
|
282
218
|
requirements:
|
283
219
|
- - ">="
|
284
220
|
- !ruby/object:Gem::Version
|
285
|
-
hash: 3
|
286
|
-
segments:
|
287
|
-
- 0
|
288
221
|
version: "0"
|
289
222
|
requirements: []
|
290
223
|
|
291
224
|
rubyforge_project: data_miner
|
292
|
-
rubygems_version: 1.
|
225
|
+
rubygems_version: 1.6.2
|
293
226
|
signing_key:
|
294
227
|
specification_version: 3
|
295
228
|
summary: Mine remote data into your ActiveRecord models.
|
data/lib/data_miner/schema.rb
DELETED
@@ -1,241 +0,0 @@
|
|
1
|
-
require 'blockenspiel'
|
2
|
-
class DataMiner
|
3
|
-
class Schema
|
4
|
-
include ::Blockenspiel::DSL
|
5
|
-
|
6
|
-
attr_reader :config
|
7
|
-
attr_reader :create_table_options
|
8
|
-
|
9
|
-
def initialize(config, create_table_options)
|
10
|
-
@config = config
|
11
|
-
@create_table_options = create_table_options.dup
|
12
|
-
@create_table_options.stringify_keys!
|
13
|
-
raise "'id' => true is not allowed in create_table_options." if @create_table_options['id'] === true
|
14
|
-
raise "'primary_key' is not allowed in create_table_options. Use set_primary_key instead." if @create_table_options.has_key?('primary_key')
|
15
|
-
@create_table_options['id'] = false # always
|
16
|
-
end
|
17
|
-
|
18
|
-
def resource
|
19
|
-
config.resource
|
20
|
-
end
|
21
|
-
|
22
|
-
# sabshere 1/25/11 what if there were multiple connections
|
23
|
-
# blockenspiel doesn't like to delegate this to #resource
|
24
|
-
def connection
|
25
|
-
::ActiveRecord::Base.connection
|
26
|
-
end
|
27
|
-
|
28
|
-
def table_name
|
29
|
-
resource.table_name
|
30
|
-
end
|
31
|
-
|
32
|
-
def ideal_table
|
33
|
-
@ideal_table ||= ::ActiveRecord::ConnectionAdapters::TableDefinition.new connection
|
34
|
-
end
|
35
|
-
|
36
|
-
def ideal_indexes
|
37
|
-
@ideal_indexes ||= []
|
38
|
-
end
|
39
|
-
|
40
|
-
def actual_indexes
|
41
|
-
connection.indexes table_name
|
42
|
-
end
|
43
|
-
|
44
|
-
def description
|
45
|
-
"Define a table called #{table_name} with primary key #{ideal_primary_key_name}"
|
46
|
-
end
|
47
|
-
|
48
|
-
def inspect
|
49
|
-
%{#<DataMiner::Schema(#{resource}): #{description}>}
|
50
|
-
end
|
51
|
-
|
52
|
-
# sabshere 1/25/11 lifted straight from activerecord-3.0.3/lib/active_record/connection_adapters/abstract/schema_definitions.rb
|
53
|
-
%w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type|
|
54
|
-
class_eval <<-EOV
|
55
|
-
def #{column_type}(*args) # def string(*args)
|
56
|
-
options = args.extract_options! # options = args.extract_options!
|
57
|
-
column_names = args # column_names = args
|
58
|
-
#
|
59
|
-
column_names.each { |name| ideal_table.column(name, '#{column_type}', options) } # column_names.each { |name| ideal_table.column(name, 'string', options) }
|
60
|
-
end # end
|
61
|
-
EOV
|
62
|
-
end
|
63
|
-
def column(*args)
|
64
|
-
ideal_table.column(*args)
|
65
|
-
end
|
66
|
-
|
67
|
-
MAX_INDEX_NAME_LENGTH = 32
|
68
|
-
def index(columns, options = {})
|
69
|
-
options = options.dup
|
70
|
-
options.stringify_keys!
|
71
|
-
columns = ::Array.wrap columns
|
72
|
-
unless name = options['name']
|
73
|
-
default_name = connection.index_name(table_name, options.symbolize_keys.merge(:column => columns))
|
74
|
-
name = default_name.length < MAX_INDEX_NAME_LENGTH ? default_name : default_name[0..MAX_INDEX_NAME_LENGTH-11] + ::Zlib.crc32(default_name).to_s
|
75
|
-
end
|
76
|
-
index_unique = options.has_key?('unique') ? options['unique'] : true
|
77
|
-
ideal_indexes.push ::ActiveRecord::ConnectionAdapters::IndexDefinition.new(table_name, name, index_unique, columns)
|
78
|
-
nil
|
79
|
-
end
|
80
|
-
|
81
|
-
def ideal_primary_key_name
|
82
|
-
resource.primary_key.to_s
|
83
|
-
end
|
84
|
-
|
85
|
-
def actual_primary_key_name
|
86
|
-
connection.primary_key(table_name).to_s
|
87
|
-
end
|
88
|
-
|
89
|
-
INDEX_PROPERTIES = %w{ name columns }
|
90
|
-
def index_equivalent?(a, b)
|
91
|
-
return false unless a and b
|
92
|
-
INDEX_PROPERTIES.all? do |property|
|
93
|
-
::DataMiner.logger.debug "...comparing #{a.send(property).inspect}.to_s <-> #{b.send(property).inspect}.to_s"
|
94
|
-
a.send(property).to_s == b.send(property).to_s
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
# FIXME mysql only (assume integer primary keys)
|
99
|
-
def column_equivalent?(a, b)
|
100
|
-
return false unless a and b
|
101
|
-
a_type = a.type.to_s == 'primary_key' ? 'integer' : a.type.to_s
|
102
|
-
b_type = b.type.to_s == 'primary_key' ? 'integer' : b.type.to_s
|
103
|
-
a_type == b_type and a.name.to_s == b.name.to_s
|
104
|
-
end
|
105
|
-
|
106
|
-
%w{ column index }.each do |i|
|
107
|
-
eval %{
|
108
|
-
def #{i}_needs_to_be_placed?(name)
|
109
|
-
actual = actual_#{i} name
|
110
|
-
return true unless actual
|
111
|
-
ideal = ideal_#{i} name
|
112
|
-
not #{i}_equivalent? actual, ideal
|
113
|
-
end
|
114
|
-
|
115
|
-
def #{i}_needs_to_be_removed?(name)
|
116
|
-
ideal_#{i}(name).nil?
|
117
|
-
end
|
118
|
-
}
|
119
|
-
end
|
120
|
-
|
121
|
-
def ideal_column(name)
|
122
|
-
ideal_table[name.to_s]
|
123
|
-
end
|
124
|
-
|
125
|
-
def actual_column(name)
|
126
|
-
resource.columns_hash[name.to_s]
|
127
|
-
end
|
128
|
-
|
129
|
-
def ideal_index(name)
|
130
|
-
ideal_indexes.detect { |ideal| ideal.name == name.to_s }
|
131
|
-
end
|
132
|
-
|
133
|
-
def actual_index(name)
|
134
|
-
actual_indexes.detect { |actual| actual.name == name.to_s }
|
135
|
-
end
|
136
|
-
|
137
|
-
def place_column(name)
|
138
|
-
remove_column name if actual_column name
|
139
|
-
ideal = ideal_column name
|
140
|
-
::DataMiner.logger.debug "ADDING COLUMN #{name}"
|
141
|
-
connection.add_column table_name, name, ideal.type.to_sym # symbol type!
|
142
|
-
resource.reset_column_information
|
143
|
-
end
|
144
|
-
|
145
|
-
def remove_column(name)
|
146
|
-
::DataMiner.logger.debug "REMOVING COLUMN #{name}"
|
147
|
-
connection.remove_column table_name, name
|
148
|
-
resource.reset_column_information
|
149
|
-
end
|
150
|
-
|
151
|
-
def place_index(name)
|
152
|
-
remove_index name if actual_index name
|
153
|
-
ideal = ideal_index name
|
154
|
-
::DataMiner.logger.debug "ADDING INDEX #{name}"
|
155
|
-
connection.add_index table_name, ideal.columns, :name => ideal.name
|
156
|
-
resource.reset_column_information
|
157
|
-
end
|
158
|
-
|
159
|
-
def remove_index(name)
|
160
|
-
::DataMiner.logger.debug "REMOVING INDEX #{name}"
|
161
|
-
connection.remove_index table_name, :name => name
|
162
|
-
resource.reset_column_information
|
163
|
-
end
|
164
|
-
|
165
|
-
def run
|
166
|
-
_create_table
|
167
|
-
_set_primary_key
|
168
|
-
_remove_columns
|
169
|
-
_add_columns
|
170
|
-
_remove_indexes
|
171
|
-
_add_indexes
|
172
|
-
nil
|
173
|
-
end
|
174
|
-
|
175
|
-
def _create_table
|
176
|
-
if not resource.table_exists?
|
177
|
-
create_table_options = @create_table_options.dup
|
178
|
-
create_table_options.symbolize_keys!
|
179
|
-
::DataMiner.logger.debug "CREATING TABLE #{table_name} with #{create_table_options.inspect}"
|
180
|
-
connection.create_table table_name, create_table_options do |t|
|
181
|
-
t.integer 'data_miner_placeholder'
|
182
|
-
end
|
183
|
-
resource.reset_column_information
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
# FIXME mysql only
|
188
|
-
def _set_primary_key
|
189
|
-
if ideal_primary_key_name == 'id' and not ideal_column('id')
|
190
|
-
::DataMiner.logger.debug "no special primary key set on #{table_name}, so using 'id'"
|
191
|
-
column 'id', :primary_key # needs to be a sym?
|
192
|
-
end
|
193
|
-
actual = actual_column actual_primary_key_name
|
194
|
-
ideal = ideal_column ideal_primary_key_name
|
195
|
-
if not column_equivalent? actual, ideal
|
196
|
-
::DataMiner.logger.debug "looks like #{table_name} has a bad (or missing) primary key"
|
197
|
-
if actual
|
198
|
-
::DataMiner.logger.debug "looks like primary key needs to change from #{actual_primary_key_name} to #{ideal_primary_key_name}, re-creating #{table_name} from scratch"
|
199
|
-
connection.drop_table table_name
|
200
|
-
resource.reset_column_information
|
201
|
-
_create_table
|
202
|
-
end
|
203
|
-
place_column ideal_primary_key_name
|
204
|
-
unless ideal.type.to_s == 'primary_key'
|
205
|
-
::DataMiner.logger.debug "SETTING #{ideal_primary_key_name} AS PRIMARY KEY"
|
206
|
-
if connection.adapter_name.downcase == 'sqlite'
|
207
|
-
connection.execute "CREATE UNIQUE INDEX IDX_#{table_name}_#{ideal_primary_key_name} ON #{table_name} (#{ideal_primary_key_name} ASC)"
|
208
|
-
else
|
209
|
-
connection.execute "ALTER TABLE `#{table_name}` ADD PRIMARY KEY (`#{ideal_primary_key_name}`)"
|
210
|
-
end
|
211
|
-
end
|
212
|
-
end
|
213
|
-
resource.reset_column_information
|
214
|
-
end
|
215
|
-
|
216
|
-
def _remove_columns
|
217
|
-
resource.columns_hash.values.each do |actual|
|
218
|
-
remove_column actual.name if column_needs_to_be_removed? actual.name
|
219
|
-
end
|
220
|
-
end
|
221
|
-
|
222
|
-
def _add_columns
|
223
|
-
ideal_table.columns.each do |ideal|
|
224
|
-
place_column ideal.name if column_needs_to_be_placed? ideal.name
|
225
|
-
end
|
226
|
-
end
|
227
|
-
|
228
|
-
def _remove_indexes
|
229
|
-
actual_indexes.each do |actual|
|
230
|
-
remove_index actual.name if index_needs_to_be_removed? actual.name
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
|
-
def _add_indexes
|
235
|
-
ideal_indexes.each do |ideal|
|
236
|
-
next if ideal.name == ideal_primary_key_name # this should already have been taken care of
|
237
|
-
place_index ideal.name if index_needs_to_be_placed? ideal.name
|
238
|
-
end
|
239
|
-
end
|
240
|
-
end
|
241
|
-
end
|