ncs_mdes_warehouse 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +21 -0
- data/lib/ncs_navigator/warehouse/cli.rb +3 -2
- data/lib/ncs_navigator/warehouse/configuration.rb +1 -1
- data/lib/ncs_navigator/warehouse/database_initializer.rb +25 -9
- data/lib/ncs_navigator/warehouse/transform_load.rb +16 -6
- data/lib/ncs_navigator/warehouse/transformers.rb +1 -0
- data/lib/ncs_navigator/warehouse/transformers/database.rb +18 -8
- data/lib/ncs_navigator/warehouse/transformers/sampling_units.rb +96 -0
- data/lib/ncs_navigator/warehouse/transformers/vdr_xml.rb +13 -1
- data/lib/ncs_navigator/warehouse/version.rb +1 -1
- data/ncs_mdes_warehouse.gemspec +3 -3
- data/spec/navigator.ini +2 -1
- data/spec/ncs_navigator/warehouse/configuration_spec.rb +3 -3
- data/spec/ncs_navigator/warehouse/transform_load_spec.rb +17 -0
- data/spec/ncs_navigator/warehouse/transformers/database_spec.rb +11 -4
- data/spec/ncs_navigator/warehouse/transformers/sampling_units_spec.rb +103 -0
- data/spec/ncs_navigator/warehouse/transformers/vdr_xml_spec.rb +34 -4
- data/spec/ncs_navigator/warehouse/xml_emitter_spec.rb +2 -2
- data/spec/test_samples.csv +2 -1
- metadata +41 -44
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,27 @@
|
|
1
1
|
NCS Navigator MDES Warehouse History
|
2
2
|
====================================
|
3
3
|
|
4
|
+
0.1.1
|
5
|
+
-----
|
6
|
+
|
7
|
+
- Disable DataMapper's identity map during ETL. It caches created
|
8
|
+
records in memory without limit, so it brings the system to a crawl
|
9
|
+
when loading hundreds of thousands of records.
|
10
|
+
|
11
|
+
- Wrap each transformer in a transaction during ETL, and turn off
|
12
|
+
synchronous commits. This combination (not tried separately) gives
|
13
|
+
around a 10% speed boost.
|
14
|
+
|
15
|
+
- Loosen gem dependencies for compatibility with Rails 3.0.
|
16
|
+
|
17
|
+
- Add `Transformers::SamplingUnits` for generating PSU, SSU, and TSU
|
18
|
+
records from the runtime configuration. (#1602)
|
19
|
+
|
20
|
+
- Changed default log path to `/var/log/nubic/ncs/warehouse`. This is
|
21
|
+
parallel with the default configuration paths under `/etc`. (#1605)
|
22
|
+
|
23
|
+
- Improve error messages in `VdrXml.from_most_recent_file`. (#1604)
|
24
|
+
|
4
25
|
0.1.0
|
5
26
|
-----
|
6
27
|
|
@@ -43,7 +43,8 @@ module NcsNavigator::Warehouse
|
|
43
43
|
desc 'clone-working', 'Copies the contents of the working database to the reporting database'
|
44
44
|
def clone_working
|
45
45
|
db = DatabaseInitializer.new(configuration)
|
46
|
-
db.
|
46
|
+
db.set_up_repository(:both)
|
47
|
+
db.clone_working_to_reporting or exit(1)
|
47
48
|
end
|
48
49
|
|
49
50
|
desc 'emit-xml [FILENAME]', 'Generates the VDR submission XML'
|
@@ -74,7 +75,7 @@ DESC
|
|
74
75
|
|
75
76
|
success = TransformLoad.new(configuration).run
|
76
77
|
if success || options['force']
|
77
|
-
db.clone_working_to_reporting
|
78
|
+
db.clone_working_to_reporting or exit(1)
|
78
79
|
else
|
79
80
|
configuration.shell.say_line "There were errors during ETL. Reporting database not updated."
|
80
81
|
configuration.shell.say_line "See the log and the database table wh_transform_error for more details."
|
@@ -80,11 +80,7 @@ module NcsNavigator::Warehouse
|
|
80
80
|
#
|
81
81
|
# @return [void]
|
82
82
|
def replace_schema
|
83
|
-
|
84
|
-
log.info "Dropping everything in working schema"
|
85
|
-
::DataMapper.repository(:mdes_warehouse_working).adapter.
|
86
|
-
execute("DROP OWNED BY #{params(:working)['username']}")
|
87
|
-
shell.clear_line_then_say "Dropped everything in working schema.\n"
|
83
|
+
drop_all(:working)
|
88
84
|
|
89
85
|
shell.say "Loading MDES models..."
|
90
86
|
log.info "Initializing schema for MDES #{configuration.mdes.specification_version}"
|
@@ -98,11 +94,23 @@ module NcsNavigator::Warehouse
|
|
98
94
|
"Added #{configuration.models_module.mdes_order.size} MDES tables.\n")
|
99
95
|
end
|
100
96
|
|
97
|
+
def drop_all(which)
|
98
|
+
shell.say "Dropping everything in #{which} schema"
|
99
|
+
log.info "Dropping everything in #{which} schema"
|
100
|
+
::DataMapper.repository(:"mdes_warehouse_#{which}").adapter.
|
101
|
+
execute("DROP OWNED BY #{params(which)['username']}")
|
102
|
+
shell.clear_line_then_say "Dropped everything in #{which} schema.\n"
|
103
|
+
end
|
104
|
+
private :drop_all
|
105
|
+
|
101
106
|
##
|
102
107
|
# Replaces the reporting database with a clone of the working
|
103
108
|
# database. This method relies on the command line `pg_dump` and
|
104
|
-
# `pg_restore` commands.
|
109
|
+
# `pg_restore` commands. In addition, you must also have
|
110
|
+
# previously called {#set_up_repository} with `:both` as the
|
111
|
+
# argument.
|
105
112
|
#
|
113
|
+
# @return [true,false] whether the clone succeeded.
|
106
114
|
# @see Configuration#pg_bin_path
|
107
115
|
def clone_working_to_reporting
|
108
116
|
PostgreSQL::Pgpass.new.tap do |pgpass|
|
@@ -121,16 +129,24 @@ module NcsNavigator::Warehouse
|
|
121
129
|
configuration.pg_bin('pg_restore'),
|
122
130
|
pg_params(params(:reporting)),
|
123
131
|
'--schema', 'public',
|
124
|
-
'--clean',
|
125
132
|
'--dbname', params(:reporting)['database']
|
126
133
|
].flatten
|
127
134
|
|
135
|
+
drop_all(:reporting)
|
136
|
+
|
128
137
|
command = "#{escape_cmd dump_cmd} | #{escape_cmd restore_cmd}"
|
138
|
+
shell.say 'Cloning working schema into reporting schema...'
|
129
139
|
log.info('Cloning working schema into reporting schema')
|
130
140
|
log.debug("Clone command: #{command.inspect}")
|
131
141
|
unless system(command)
|
132
|
-
|
133
|
-
|
142
|
+
shell.clear_line_then_say(
|
143
|
+
"Clone from working to reporting failed. See above for detail.\n")
|
144
|
+
log.error('Clone failed.')
|
145
|
+
return false
|
146
|
+
else
|
147
|
+
shell.clear_line_then_say("Clone from working to reporting successful.\n")
|
148
|
+
log.info('Clone succeeded.')
|
149
|
+
return true
|
134
150
|
end
|
135
151
|
end
|
136
152
|
|
@@ -18,13 +18,23 @@ module NcsNavigator::Warehouse
|
|
18
18
|
def run
|
19
19
|
position = 0
|
20
20
|
@statuses = configuration.transformers.collect do |transformer|
|
21
|
-
::DataMapper.repository(:mdes_warehouse_working) do
|
21
|
+
::DataMapper.repository(:mdes_warehouse_working) do |repo|
|
22
|
+
# redefine identity map as a no-op so it doesn't cache
|
23
|
+
# anything. TODO: provide a patch to DataMapper that makes
|
24
|
+
# something like this an option.
|
25
|
+
def repo.identity_map(model); {}; end
|
26
|
+
|
22
27
|
build_status_for(transformer, position).tap do |status|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
+
TransformStatus.transaction do
|
29
|
+
if repo.adapter.to_s =~ /Postgres/
|
30
|
+
repo.adapter.execute("SET LOCAL synchronous_commit TO OFF")
|
31
|
+
end
|
32
|
+
begin
|
33
|
+
transformer.transform(status)
|
34
|
+
rescue => e
|
35
|
+
shell.say_line("\nTransform failed. (See log for more detail.)")
|
36
|
+
status.add_error("Transform failed. #{e.class}: #{e}.")
|
37
|
+
end
|
28
38
|
end
|
29
39
|
status.end_time = Time.now
|
30
40
|
unless status.save
|
@@ -13,6 +13,7 @@ module NcsNavigator::Warehouse
|
|
13
13
|
module Transformers
|
14
14
|
autoload :Database, 'ncs_navigator/warehouse/transformers/database'
|
15
15
|
autoload :EnumTransformer, 'ncs_navigator/warehouse/transformers/enum_transformer'
|
16
|
+
autoload :SamplingUnits, 'ncs_navigator/warehouse/transformers/sampling_units'
|
16
17
|
autoload :VdrXml, 'ncs_navigator/warehouse/transformers/vdr_xml'
|
17
18
|
end
|
18
19
|
end
|
@@ -287,13 +287,12 @@ module NcsNavigator::Warehouse::Transformers
|
|
287
287
|
#
|
288
288
|
# @return [void]
|
289
289
|
def produce_one_for_one(name, model, options={})
|
290
|
-
options[:on_unused] ||= on_unused_columns
|
291
290
|
options[:column_map] =
|
292
291
|
(options[:column_map] || {}).inject({}) { |h, (k, v)| h[k.to_s] = v.to_s; h }
|
293
|
-
options[:ignored_columns] =
|
294
|
-
(options[:ignored_columns] || []).collect(&:to_s) + ignored_columns
|
292
|
+
options[:ignored_columns] = (options[:ignored_columns] || []).collect(&:to_s)
|
295
293
|
|
296
|
-
record_producers <<
|
294
|
+
record_producers <<
|
295
|
+
OneForOneProducer.new(name, options.delete(:query), model, self, options)
|
297
296
|
end
|
298
297
|
end
|
299
298
|
|
@@ -308,11 +307,12 @@ module NcsNavigator::Warehouse::Transformers
|
|
308
307
|
##
|
309
308
|
# The class encapsulating one call to {DSL#produce_one_for_one}
|
310
309
|
class OneForOneProducer < RecordProducer
|
311
|
-
attr_reader :model, :options
|
310
|
+
attr_reader :model, :options, :dsl_host
|
312
311
|
|
313
|
-
def initialize(name, query, model, options)
|
312
|
+
def initialize(name, query, model, dsl_host, options)
|
314
313
|
super(name, query, self)
|
315
314
|
@model = model
|
315
|
+
@dsl_host = dsl_host
|
316
316
|
@options = options
|
317
317
|
end
|
318
318
|
|
@@ -321,9 +321,9 @@ module NcsNavigator::Warehouse::Transformers
|
|
321
321
|
# row as mapped by {#column_map}.
|
322
322
|
def convert_row(row)
|
323
323
|
col_map = column_map(row.members)
|
324
|
-
unused = row.members.collect(&:to_s) - col_map.keys -
|
324
|
+
unused = row.members.collect(&:to_s) - col_map.keys - ignored_columns
|
325
325
|
|
326
|
-
if
|
326
|
+
if on_unused == :fail && !unused.empty?
|
327
327
|
raise UnusedColumnsForModelError.new(unused)
|
328
328
|
end
|
329
329
|
model.new(
|
@@ -374,6 +374,16 @@ module NcsNavigator::Warehouse::Transformers
|
|
374
374
|
end
|
375
375
|
end
|
376
376
|
private :prefixed_property_name
|
377
|
+
|
378
|
+
def on_unused
|
379
|
+
options[:on_unused] || dsl_host.on_unused_columns
|
380
|
+
end
|
381
|
+
private :on_unused
|
382
|
+
|
383
|
+
def ignored_columns
|
384
|
+
options[:ignored_columns] + dsl_host.ignored_columns
|
385
|
+
end
|
386
|
+
private :ignored_columns
|
377
387
|
end
|
378
388
|
|
379
389
|
##
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'ncs_navigator/warehouse'
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
module NcsNavigator::Warehouse::Transformers
|
6
|
+
##
|
7
|
+
# An enumerator that yields the sampling unit records implied by the
|
8
|
+
# current `NcsNavigator::Configuration`.
|
9
|
+
#
|
10
|
+
# @see Configuration#navigator
|
11
|
+
class SamplingUnits
|
12
|
+
include Enumerable
|
13
|
+
extend Forwardable
|
14
|
+
|
15
|
+
attr_reader :configuration
|
16
|
+
def_delegators :configuration, :shell, :log
|
17
|
+
|
18
|
+
def self.create_transformer(config)
|
19
|
+
EnumTransformer.new(config, new(config))
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(config)
|
23
|
+
@configuration = config
|
24
|
+
end
|
25
|
+
|
26
|
+
def each
|
27
|
+
log.info("Generating MDES records for sampling units.")
|
28
|
+
|
29
|
+
shell_describe('PSU', configuration.navigator.psus.size)
|
30
|
+
configuration.navigator.psus.each do |nav_psu|
|
31
|
+
yield create_psu(nav_psu)
|
32
|
+
end
|
33
|
+
|
34
|
+
shell_describe('SSU', configuration.navigator.ssus.size)
|
35
|
+
configuration.navigator.ssus.each do |nav_ssu|
|
36
|
+
yield create_ssu(nav_ssu)
|
37
|
+
end
|
38
|
+
|
39
|
+
tsus = configuration.navigator.ssus.collect { |nav_ssu| nav_ssu.tsus }.flatten
|
40
|
+
shell_describe('TSU', tsus.size)
|
41
|
+
tsus.each do |nav_tsu|
|
42
|
+
yield create_tsu(nav_tsu)
|
43
|
+
end
|
44
|
+
|
45
|
+
log.info("All sampling unit records generated.")
|
46
|
+
shell.clear_line_then_say("All sampling unit records generated.\n")
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def shell_describe(what, count)
|
52
|
+
plural = ('s' if count != 1)
|
53
|
+
shell.clear_line_then_say("Generating MDES record#{plural} for #{count} #{what}#{plural}")
|
54
|
+
end
|
55
|
+
|
56
|
+
def psu_model
|
57
|
+
configuration.models_module.const_get(:Psu)
|
58
|
+
end
|
59
|
+
|
60
|
+
def create_psu(nav_psu)
|
61
|
+
psu_model.new(
|
62
|
+
:psu_id => nav_psu.id,
|
63
|
+
:sc_id => configuration.navigator.sc_id,
|
64
|
+
:recruit_type => configuration.navigator.recruitment_type_id,
|
65
|
+
:psu_name => configuration.mdes.types.detect { |t| t.name == 'psu_cl1' }.code_list.
|
66
|
+
detect { |code| code.value == nav_psu.id }.label
|
67
|
+
)
|
68
|
+
end
|
69
|
+
|
70
|
+
def ssu_model
|
71
|
+
configuration.models_module.const_get(:Ssu)
|
72
|
+
end
|
73
|
+
|
74
|
+
def create_ssu(nav_ssu)
|
75
|
+
ssu_model.new(
|
76
|
+
:ssu_id => nav_ssu.id,
|
77
|
+
:ssu_name => nav_ssu.name,
|
78
|
+
:psu_id => nav_ssu.psu.id,
|
79
|
+
:sc_id => configuration.navigator.sc_id
|
80
|
+
)
|
81
|
+
end
|
82
|
+
|
83
|
+
def tsu_model
|
84
|
+
configuration.models_module.const_get(:Tsu)
|
85
|
+
end
|
86
|
+
|
87
|
+
def create_tsu(nav_tsu)
|
88
|
+
tsu_model.new(
|
89
|
+
:tsu_id => nav_tsu.id,
|
90
|
+
:tsu_name => nav_tsu.name,
|
91
|
+
:psu_id => nav_tsu.ssu.psu.id,
|
92
|
+
:sc_id => configuration.navigator.sc_id
|
93
|
+
)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -13,12 +13,24 @@ module NcsNavigator::Warehouse::Transformers
|
|
13
13
|
end
|
14
14
|
|
15
15
|
##
|
16
|
+
# @param config [Configuration] the configuration for the
|
17
|
+
# warehouse.
|
18
|
+
# @param list [String,Array<String>] the files to consider. This
|
19
|
+
# may be either a glob or an explicit list of files.
|
20
|
+
#
|
16
21
|
# @return [#transform] a transformer for the most recently
|
17
22
|
# modified VDR XML file from the given list of files.
|
18
23
|
def from_most_recent_file(config, list)
|
24
|
+
files =
|
25
|
+
if String === list
|
26
|
+
Dir[list].tap { |a| fail "Glob #{list} does not match any files." if a.empty? }
|
27
|
+
else
|
28
|
+
list.tap { |a| fail "The file list is empty." if a.empty? }
|
29
|
+
end
|
30
|
+
|
19
31
|
from_file(
|
20
32
|
config,
|
21
|
-
|
33
|
+
files.collect { |fn| [fn, File.stat(fn).mtime] }.
|
22
34
|
sort_by { |fn, mtime| mtime }.reverse.first.first)
|
23
35
|
end
|
24
36
|
end
|
data/ncs_mdes_warehouse.gemspec
CHANGED
@@ -16,16 +16,16 @@ Gem::Specification.new do |s|
|
|
16
16
|
s.require_paths = ["lib", "generated_models"]
|
17
17
|
|
18
18
|
s.add_dependency 'ncs_mdes', '~> 0.4', '>= 0.4.2'
|
19
|
-
s.add_dependency 'ncs_navigator_configuration', '~> 0.
|
19
|
+
s.add_dependency 'ncs_navigator_configuration', '~> 0.2'
|
20
20
|
|
21
21
|
s.add_dependency 'activesupport', '~> 3.0'
|
22
|
-
s.add_dependency 'i18n', '~> 0.
|
22
|
+
s.add_dependency 'i18n', '~> 0.4' # required by activesupport
|
23
23
|
|
24
24
|
s.add_dependency 'thor', '~> 0.14.6'
|
25
25
|
s.add_dependency 'rubyzip', '~> 0.9.4'
|
26
26
|
|
27
27
|
s.add_dependency 'nokogiri', '~> 1.5.0'
|
28
|
-
s.add_dependency 'builder', '
|
28
|
+
s.add_dependency 'builder', '>= 2.1.2'
|
29
29
|
|
30
30
|
s.add_dependency 'data_mapper', '~> 1.2.0'
|
31
31
|
s.add_dependency 'bcdatabase', '~> 1.1'
|
data/spec/navigator.ini
CHANGED
@@ -157,8 +157,8 @@ module NcsNavigator::Warehouse
|
|
157
157
|
end
|
158
158
|
|
159
159
|
describe 'by default' do
|
160
|
-
it 'is /var/log/ncs/warehouse/{env_name}.log' do
|
161
|
-
config.log_file.to_s.should == '/var/log/ncs/warehouse/the_moon.log'
|
160
|
+
it 'is /var/log/nubic/ncs/warehouse/{env_name}.log' do
|
161
|
+
config.log_file.to_s.should == '/var/log/nubic/ncs/warehouse/the_moon.log'
|
162
162
|
end
|
163
163
|
|
164
164
|
it 'is a Pathname' do
|
@@ -187,7 +187,7 @@ module NcsNavigator::Warehouse
|
|
187
187
|
end
|
188
188
|
|
189
189
|
it 'reverts to the default' do
|
190
|
-
config.log_file.to_s.should == '/var/log/ncs/warehouse/the_moon.log'
|
190
|
+
config.log_file.to_s.should == '/var/log/nubic/ncs/warehouse/the_moon.log'
|
191
191
|
end
|
192
192
|
end
|
193
193
|
|
@@ -137,6 +137,23 @@ module NcsNavigator::Warehouse
|
|
137
137
|
|
138
138
|
it 'sends on failure'
|
139
139
|
end
|
140
|
+
|
141
|
+
# This is a crappy test; it would be better if it could be done
|
142
|
+
# another way. Unfortunately, it doesn't look like DataMapper
|
143
|
+
# exposes information to allow another way to check this.
|
144
|
+
it "defeats DataMapper's caching" do
|
145
|
+
seen_maps = []
|
146
|
+
identity_map_tracker_transformer = BlockTransformer.new { |s|
|
147
|
+
seen_maps << ::DataMapper::Repository.context.first.instance_eval { @identity_maps }
|
148
|
+
}
|
149
|
+
config.add_transformer(identity_map_tracker_transformer)
|
150
|
+
config.add_transformer(identity_map_tracker_transformer)
|
151
|
+
|
152
|
+
loader.run
|
153
|
+
loader.statuses.collect { |s| s.transform_errors }.flatten.should == []
|
154
|
+
|
155
|
+
seen_maps.should == [{}, {}]
|
156
|
+
end
|
140
157
|
end
|
141
158
|
|
142
159
|
class ::BlockTransformer
|
@@ -304,14 +304,15 @@ module NcsNavigator::Warehouse::Transformers
|
|
304
304
|
|
305
305
|
describe 'when #on_unused_columns is set to :fail' do
|
306
306
|
let(:cls) {
|
307
|
-
sample_class do
|
308
|
-
on_unused_columns :fail
|
307
|
+
sample_class.tap do |c|
|
308
|
+
c.on_unused_columns :fail
|
309
|
+
c.produce_one_for_one(:addresses, address_model, options)
|
309
310
|
end
|
310
311
|
}
|
311
312
|
|
312
313
|
it 'fails appropriately' do
|
313
314
|
begin
|
314
|
-
|
315
|
+
producer.call(make_row :address_type => '-5', :address_length => '6')
|
315
316
|
fail "Exception not thrown"
|
316
317
|
rescue Database::UnusedColumnsForModelError => e
|
317
318
|
e.unused.should == %w(address_length)
|
@@ -320,7 +321,13 @@ module NcsNavigator::Warehouse::Transformers
|
|
320
321
|
|
321
322
|
it 'does not fail if the global setting is overridden' do
|
322
323
|
options[:on_unused] = :ignore
|
323
|
-
lambda {
|
324
|
+
lambda { producer.call(make_row :address_type => '-5', :address_length => '6') }.
|
325
|
+
should_not raise_error
|
326
|
+
end
|
327
|
+
|
328
|
+
it 'can be ignored by modifying the global setting' do
|
329
|
+
cls.on_unused_columns :ignore
|
330
|
+
lambda { producer.call(make_row :address_type => '-5', :address_length => '6') }.
|
324
331
|
should_not raise_error
|
325
332
|
end
|
326
333
|
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require File.expand_path('../../../../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
module NcsNavigator::Warehouse::Transformers
|
4
|
+
describe SamplingUnits, :use_mdes, :slow do
|
5
|
+
subject { SamplingUnits.new(spec_config) }
|
6
|
+
|
7
|
+
let(:test_sc_id) { '20000029' }
|
8
|
+
let(:test_psu_id) { '20000030' }
|
9
|
+
|
10
|
+
describe '.create_transformer' do
|
11
|
+
it 'creates a transformer' do
|
12
|
+
SamplingUnits.create_transformer(spec_config).should respond_to(:transform)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'yields everything in MDES order' do
|
17
|
+
subject.to_a.collect { |i| i.class.to_s.demodulize }.should == %w(Psu Ssu Ssu Tsu)
|
18
|
+
end
|
19
|
+
|
20
|
+
describe 'emitted PSU' do
|
21
|
+
let(:psu_model) { spec_config.models_module.const_get(:Psu) }
|
22
|
+
let(:psu) { subject.to_a.detect { |emitted| emitted.is_a?(psu_model) } }
|
23
|
+
|
24
|
+
it 'exists' do
|
25
|
+
psu.should_not be_nil
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'has the study center ID from the configuration' do
|
29
|
+
psu.sc_id.should == test_sc_id
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'has the correct ID' do
|
33
|
+
psu.psu_id.should == test_psu_id
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'has the name derived from the MDES' do
|
37
|
+
psu.psu_name.should == 'Cook County, IL (Wave 1)'
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'uses the recruitment type from the configuration' do
|
41
|
+
psu.recruit_type.should == '3'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe 'emitted SSU set' do
|
46
|
+
let(:ssu_model) { spec_config.models_module.const_get(:Ssu) }
|
47
|
+
let(:ssus) { subject.to_a.select { |emitted| emitted.is_a?(ssu_model) } }
|
48
|
+
|
49
|
+
it 'includes all the SSUs from the configuration' do
|
50
|
+
ssus.collect(&:ssu_id).sort.should == %w(24 42)
|
51
|
+
end
|
52
|
+
|
53
|
+
describe 'an exemplar' do
|
54
|
+
let(:ssu) { ssus.detect { |s| s.ssu_id == '42' } }
|
55
|
+
|
56
|
+
it 'has the name' do
|
57
|
+
ssu.ssu_name.should == 'UPT-42'
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'has the ID' do
|
61
|
+
ssu.ssu_id.should == '42'
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'has the SC ID' do
|
65
|
+
ssu.sc_id.should == '20000029'
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'has the PSU ID' do
|
69
|
+
ssu.psu_id.should == test_psu_id
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe 'emitted TSU set' do
|
75
|
+
let(:tsu_model) { spec_config.models_module.const_get(:Tsu) }
|
76
|
+
let(:tsus) { subject.to_a.select { |emitted| emitted.is_a?(tsu_model) } }
|
77
|
+
|
78
|
+
it 'includes all the TSUs from the configuration' do
|
79
|
+
tsus.collect(&:tsu_id).sort.should == %w(42-3)
|
80
|
+
end
|
81
|
+
|
82
|
+
describe 'an exemplar' do
|
83
|
+
let(:tsu) { tsus.detect { |s| s.tsu_id == '42-3' } }
|
84
|
+
|
85
|
+
it 'has the name' do
|
86
|
+
tsu.tsu_name.should == 'UPT-42X'
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'has the ID' do
|
90
|
+
tsu.tsu_id.should == '42-3'
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'has the SC ID' do
|
94
|
+
tsu.sc_id.should == '20000029'
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'has the PSU ID' do
|
98
|
+
tsu.psu_id.should == test_psu_id
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -27,7 +27,7 @@ module NcsNavigator::Warehouse::Transformers
|
|
27
27
|
|
28
28
|
describe '.from_most_recent_file' do
|
29
29
|
let(:path) { tmpdir('contractor-files') }
|
30
|
-
subject { VdrXml.from_most_recent_file(config,
|
30
|
+
subject { VdrXml.from_most_recent_file(config, list_or_glob) }
|
31
31
|
|
32
32
|
before do
|
33
33
|
system("touch -t 02030405 '#{path}/a'")
|
@@ -35,11 +35,41 @@ module NcsNavigator::Warehouse::Transformers
|
|
35
35
|
system("touch -t 02020405 '#{path}/c'")
|
36
36
|
end
|
37
37
|
|
38
|
-
|
39
|
-
|
38
|
+
describe 'with a file list' do
|
39
|
+
let(:list_or_glob) { Dir[File.join(path, '*')] }
|
40
|
+
|
41
|
+
it 'uses the most recent filename from the list' do
|
42
|
+
subject.enum.filename.should == File.join(path, 'b')
|
43
|
+
end
|
44
|
+
|
45
|
+
include_examples 'a VDR transformer'
|
46
|
+
|
47
|
+
describe 'that is empty' do
|
48
|
+
let(:list_or_glob) { [] }
|
49
|
+
|
50
|
+
it 'fails' do
|
51
|
+
lambda { subject }.should raise_error /The file list is empty./
|
52
|
+
end
|
53
|
+
end
|
40
54
|
end
|
41
55
|
|
42
|
-
|
56
|
+
describe 'with a glob' do
|
57
|
+
let(:list_or_glob) { File.join(path, '*') }
|
58
|
+
|
59
|
+
it 'uses the most recent filename matched by the glob' do
|
60
|
+
subject.enum.filename.should == File.join(path, 'b')
|
61
|
+
end
|
62
|
+
|
63
|
+
include_examples 'a VDR transformer'
|
64
|
+
|
65
|
+
describe 'when the glob does not match anything' do
|
66
|
+
let(:list_or_glob) { File.join(path, 'z*') }
|
67
|
+
|
68
|
+
it 'fails' do
|
69
|
+
lambda { subject }.should raise_error %r{Glob .*?./z\* does not match any files}
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
43
73
|
end
|
44
74
|
end
|
45
75
|
end
|
@@ -23,11 +23,11 @@ module NcsNavigator::Warehouse
|
|
23
23
|
# Most of the details of the XML are tested on the MdesModel mixin
|
24
24
|
describe 'the generated XML', :slow do
|
25
25
|
it 'includes the SC from the configuration' do
|
26
|
-
xml.xpath('//sc_id').text.should == '
|
26
|
+
xml.xpath('//sc_id').text.should == '20000029'
|
27
27
|
end
|
28
28
|
|
29
29
|
it 'includes the PSU from the configuration' do
|
30
|
-
xml.xpath('//psu_id').text.should == '
|
30
|
+
xml.xpath('//psu_id').text.should == '20000030'
|
31
31
|
end
|
32
32
|
|
33
33
|
it 'includes the appropriate specification version' do
|
data/spec/test_samples.csv
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ncs_mdes_warehouse
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-11-
|
12
|
+
date: 2011-11-18 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ncs_mdes
|
16
|
-
requirement: &
|
16
|
+
requirement: &2156621720 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -24,21 +24,21 @@ dependencies:
|
|
24
24
|
version: 0.4.2
|
25
25
|
type: :runtime
|
26
26
|
prerelease: false
|
27
|
-
version_requirements: *
|
27
|
+
version_requirements: *2156621720
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: ncs_navigator_configuration
|
30
|
-
requirement: &
|
30
|
+
requirement: &2156620240 !ruby/object:Gem::Requirement
|
31
31
|
none: false
|
32
32
|
requirements:
|
33
33
|
- - ~>
|
34
34
|
- !ruby/object:Gem::Version
|
35
|
-
version: '0.
|
35
|
+
version: '0.2'
|
36
36
|
type: :runtime
|
37
37
|
prerelease: false
|
38
|
-
version_requirements: *
|
38
|
+
version_requirements: *2156620240
|
39
39
|
- !ruby/object:Gem::Dependency
|
40
40
|
name: activesupport
|
41
|
-
requirement: &
|
41
|
+
requirement: &2156614960 !ruby/object:Gem::Requirement
|
42
42
|
none: false
|
43
43
|
requirements:
|
44
44
|
- - ~>
|
@@ -46,21 +46,21 @@ dependencies:
|
|
46
46
|
version: '3.0'
|
47
47
|
type: :runtime
|
48
48
|
prerelease: false
|
49
|
-
version_requirements: *
|
49
|
+
version_requirements: *2156614960
|
50
50
|
- !ruby/object:Gem::Dependency
|
51
51
|
name: i18n
|
52
|
-
requirement: &
|
52
|
+
requirement: &2156613720 !ruby/object:Gem::Requirement
|
53
53
|
none: false
|
54
54
|
requirements:
|
55
55
|
- - ~>
|
56
56
|
- !ruby/object:Gem::Version
|
57
|
-
version: '0.
|
57
|
+
version: '0.4'
|
58
58
|
type: :runtime
|
59
59
|
prerelease: false
|
60
|
-
version_requirements: *
|
60
|
+
version_requirements: *2156613720
|
61
61
|
- !ruby/object:Gem::Dependency
|
62
62
|
name: thor
|
63
|
-
requirement: &
|
63
|
+
requirement: &2156612920 !ruby/object:Gem::Requirement
|
64
64
|
none: false
|
65
65
|
requirements:
|
66
66
|
- - ~>
|
@@ -68,10 +68,10 @@ dependencies:
|
|
68
68
|
version: 0.14.6
|
69
69
|
type: :runtime
|
70
70
|
prerelease: false
|
71
|
-
version_requirements: *
|
71
|
+
version_requirements: *2156612920
|
72
72
|
- !ruby/object:Gem::Dependency
|
73
73
|
name: rubyzip
|
74
|
-
requirement: &
|
74
|
+
requirement: &2156612060 !ruby/object:Gem::Requirement
|
75
75
|
none: false
|
76
76
|
requirements:
|
77
77
|
- - ~>
|
@@ -79,10 +79,10 @@ dependencies:
|
|
79
79
|
version: 0.9.4
|
80
80
|
type: :runtime
|
81
81
|
prerelease: false
|
82
|
-
version_requirements: *
|
82
|
+
version_requirements: *2156612060
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: nokogiri
|
85
|
-
requirement: &
|
85
|
+
requirement: &2156611040 !ruby/object:Gem::Requirement
|
86
86
|
none: false
|
87
87
|
requirements:
|
88
88
|
- - ~>
|
@@ -90,21 +90,21 @@ dependencies:
|
|
90
90
|
version: 1.5.0
|
91
91
|
type: :runtime
|
92
92
|
prerelease: false
|
93
|
-
version_requirements: *
|
93
|
+
version_requirements: *2156611040
|
94
94
|
- !ruby/object:Gem::Dependency
|
95
95
|
name: builder
|
96
|
-
requirement: &
|
96
|
+
requirement: &2156609980 !ruby/object:Gem::Requirement
|
97
97
|
none: false
|
98
98
|
requirements:
|
99
|
-
- -
|
99
|
+
- - ! '>='
|
100
100
|
- !ruby/object:Gem::Version
|
101
|
-
version:
|
101
|
+
version: 2.1.2
|
102
102
|
type: :runtime
|
103
103
|
prerelease: false
|
104
|
-
version_requirements: *
|
104
|
+
version_requirements: *2156609980
|
105
105
|
- !ruby/object:Gem::Dependency
|
106
106
|
name: data_mapper
|
107
|
-
requirement: &
|
107
|
+
requirement: &2156609220 !ruby/object:Gem::Requirement
|
108
108
|
none: false
|
109
109
|
requirements:
|
110
110
|
- - ~>
|
@@ -112,10 +112,10 @@ dependencies:
|
|
112
112
|
version: 1.2.0
|
113
113
|
type: :runtime
|
114
114
|
prerelease: false
|
115
|
-
version_requirements: *
|
115
|
+
version_requirements: *2156609220
|
116
116
|
- !ruby/object:Gem::Dependency
|
117
117
|
name: bcdatabase
|
118
|
-
requirement: &
|
118
|
+
requirement: &2156608360 !ruby/object:Gem::Requirement
|
119
119
|
none: false
|
120
120
|
requirements:
|
121
121
|
- - ~>
|
@@ -123,10 +123,10 @@ dependencies:
|
|
123
123
|
version: '1.1'
|
124
124
|
type: :runtime
|
125
125
|
prerelease: false
|
126
|
-
version_requirements: *
|
126
|
+
version_requirements: *2156608360
|
127
127
|
- !ruby/object:Gem::Dependency
|
128
128
|
name: dm-postgres-adapter
|
129
|
-
requirement: &
|
129
|
+
requirement: &2156607420 !ruby/object:Gem::Requirement
|
130
130
|
none: false
|
131
131
|
requirements:
|
132
132
|
- - ~>
|
@@ -134,10 +134,10 @@ dependencies:
|
|
134
134
|
version: 1.2.0
|
135
135
|
type: :runtime
|
136
136
|
prerelease: false
|
137
|
-
version_requirements: *
|
137
|
+
version_requirements: *2156607420
|
138
138
|
- !ruby/object:Gem::Dependency
|
139
139
|
name: rspec
|
140
|
-
requirement: &
|
140
|
+
requirement: &2156606300 !ruby/object:Gem::Requirement
|
141
141
|
none: false
|
142
142
|
requirements:
|
143
143
|
- - ~>
|
@@ -145,10 +145,10 @@ dependencies:
|
|
145
145
|
version: '2.6'
|
146
146
|
type: :development
|
147
147
|
prerelease: false
|
148
|
-
version_requirements: *
|
148
|
+
version_requirements: *2156606300
|
149
149
|
- !ruby/object:Gem::Dependency
|
150
150
|
name: rake
|
151
|
-
requirement: &
|
151
|
+
requirement: &2156604880 !ruby/object:Gem::Requirement
|
152
152
|
none: false
|
153
153
|
requirements:
|
154
154
|
- - ~>
|
@@ -156,10 +156,10 @@ dependencies:
|
|
156
156
|
version: 0.9.2
|
157
157
|
type: :development
|
158
158
|
prerelease: false
|
159
|
-
version_requirements: *
|
159
|
+
version_requirements: *2156604880
|
160
160
|
- !ruby/object:Gem::Dependency
|
161
161
|
name: yard
|
162
|
-
requirement: &
|
162
|
+
requirement: &2156603540 !ruby/object:Gem::Requirement
|
163
163
|
none: false
|
164
164
|
requirements:
|
165
165
|
- - ~>
|
@@ -167,10 +167,10 @@ dependencies:
|
|
167
167
|
version: 0.7.2
|
168
168
|
type: :development
|
169
169
|
prerelease: false
|
170
|
-
version_requirements: *
|
170
|
+
version_requirements: *2156603540
|
171
171
|
- !ruby/object:Gem::Dependency
|
172
172
|
name: ci_reporter
|
173
|
-
requirement: &
|
173
|
+
requirement: &2156602740 !ruby/object:Gem::Requirement
|
174
174
|
none: false
|
175
175
|
requirements:
|
176
176
|
- - ~>
|
@@ -178,10 +178,10 @@ dependencies:
|
|
178
178
|
version: 1.6.5
|
179
179
|
type: :development
|
180
180
|
prerelease: false
|
181
|
-
version_requirements: *
|
181
|
+
version_requirements: *2156602740
|
182
182
|
- !ruby/object:Gem::Dependency
|
183
183
|
name: fakefs
|
184
|
-
requirement: &
|
184
|
+
requirement: &2156601440 !ruby/object:Gem::Requirement
|
185
185
|
none: false
|
186
186
|
requirements:
|
187
187
|
- - ~>
|
@@ -189,7 +189,7 @@ dependencies:
|
|
189
189
|
version: 0.4.0
|
190
190
|
type: :development
|
191
191
|
prerelease: false
|
192
|
-
version_requirements: *
|
192
|
+
version_requirements: *2156601440
|
193
193
|
description:
|
194
194
|
email:
|
195
195
|
- r-sutphin@northwestern.edu
|
@@ -493,6 +493,7 @@ files:
|
|
493
493
|
- lib/ncs_navigator/warehouse/transformers.rb
|
494
494
|
- lib/ncs_navigator/warehouse/transformers/database.rb
|
495
495
|
- lib/ncs_navigator/warehouse/transformers/enum_transformer.rb
|
496
|
+
- lib/ncs_navigator/warehouse/transformers/sampling_units.rb
|
496
497
|
- lib/ncs_navigator/warehouse/transformers/vdr_xml.rb
|
497
498
|
- lib/ncs_navigator/warehouse/transformers/vdr_xml/reader.rb
|
498
499
|
- lib/ncs_navigator/warehouse/updating_shell.rb
|
@@ -512,6 +513,7 @@ files:
|
|
512
513
|
- spec/ncs_navigator/warehouse/transform_load_spec.rb
|
513
514
|
- spec/ncs_navigator/warehouse/transformers/database_spec.rb
|
514
515
|
- spec/ncs_navigator/warehouse/transformers/enum_transformer_spec.rb
|
516
|
+
- spec/ncs_navigator/warehouse/transformers/sampling_units_spec.rb
|
515
517
|
- spec/ncs_navigator/warehouse/transformers/vdr_xml/made_up_vdr_xml.xml
|
516
518
|
- spec/ncs_navigator/warehouse/transformers/vdr_xml/reader_spec.rb
|
517
519
|
- spec/ncs_navigator/warehouse/transformers/vdr_xml_spec.rb
|
@@ -532,18 +534,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
532
534
|
- - ! '>='
|
533
535
|
- !ruby/object:Gem::Version
|
534
536
|
version: '0'
|
535
|
-
segments:
|
536
|
-
- 0
|
537
|
-
hash: -4006681032861892905
|
538
537
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
539
538
|
none: false
|
540
539
|
requirements:
|
541
540
|
- - ! '>='
|
542
541
|
- !ruby/object:Gem::Version
|
543
542
|
version: '0'
|
544
|
-
segments:
|
545
|
-
- 0
|
546
|
-
hash: -4006681032861892905
|
547
543
|
requirements: []
|
548
544
|
rubyforge_project:
|
549
545
|
rubygems_version: 1.8.10
|
@@ -564,6 +560,7 @@ test_files:
|
|
564
560
|
- spec/ncs_navigator/warehouse/transform_load_spec.rb
|
565
561
|
- spec/ncs_navigator/warehouse/transformers/database_spec.rb
|
566
562
|
- spec/ncs_navigator/warehouse/transformers/enum_transformer_spec.rb
|
563
|
+
- spec/ncs_navigator/warehouse/transformers/sampling_units_spec.rb
|
567
564
|
- spec/ncs_navigator/warehouse/transformers/vdr_xml/made_up_vdr_xml.xml
|
568
565
|
- spec/ncs_navigator/warehouse/transformers/vdr_xml/reader_spec.rb
|
569
566
|
- spec/ncs_navigator/warehouse/transformers/vdr_xml_spec.rb
|