data_miner 1.1.8 → 1.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.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
|