ncs_mdes_warehouse 0.8.0 → 0.9.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/CHANGELOG.md +13 -0
- data/lib/ncs_navigator/warehouse/configuration.rb +21 -1
- data/lib/ncs_navigator/warehouse/transformers/database.rb +34 -13
- data/lib/ncs_navigator/warehouse/version.rb +1 -1
- data/spec/ncs_navigator/warehouse/configuration_spec.rb +6 -0
- data/spec/ncs_navigator/warehouse/transformers/database_spec.rb +38 -7
- metadata +8 -2
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,19 @@
|
|
1
1
|
NCS Navigator MDES Warehouse History
|
2
2
|
====================================
|
3
3
|
|
4
|
+
0.9.0
|
5
|
+
-----
|
6
|
+
|
7
|
+
- Support symbolic references to models in `produce_one_for_one` in the database
|
8
|
+
transformer DSL. This results in a minor *BREAKING CHANGE*:
|
9
|
+
`Database::DSL::OneToOneProducer#model` has been renamed `model_or_name` and
|
10
|
+
may give you either the model or a symbolic reference to it. There is a new
|
11
|
+
method `#model(configuration)` which takes a configuration instance and always
|
12
|
+
gives you a model. Similarly, `Database::DSL::OneToOneProducer#column_map` now
|
13
|
+
requires a configuration instance as a second parameter. (#2552)
|
14
|
+
|
15
|
+
- Fix probably-never-functional `Configuration#mdes_version` reader. (#2553)
|
16
|
+
|
4
17
|
0.8.0
|
5
18
|
-----
|
6
19
|
|
@@ -157,9 +157,24 @@ module NcsNavigator::Warehouse
|
|
157
157
|
|
158
158
|
@models_module = NcsNavigator::Warehouse::Models.const_get module_name
|
159
159
|
end
|
160
|
-
attr_reader :mdes_version
|
161
160
|
|
162
161
|
##
|
162
|
+
# Returns the configured MDES version string.
|
163
|
+
#
|
164
|
+
# N.b.: this method triggers loading the default MDES module and
|
165
|
+
# specification if {#mdes_version=} has not been called yet.
|
166
|
+
#
|
167
|
+
# @return [String] the configured MDES version.
|
168
|
+
def mdes_version
|
169
|
+
mdes.version
|
170
|
+
end
|
171
|
+
|
172
|
+
##
|
173
|
+
# Returns the specification for the active MDES version.
|
174
|
+
#
|
175
|
+
# N.b.: this method triggers loading the default MDES module and
|
176
|
+
# specification if {#mdes_version=} has not been called yet.
|
177
|
+
#
|
163
178
|
# @return [NcsNavigator::Mdes::Specification] the specification
|
164
179
|
# (provided by `ncs_mdes`) for the active MDES version.
|
165
180
|
def mdes
|
@@ -169,6 +184,11 @@ module NcsNavigator::Warehouse
|
|
169
184
|
attr_writer :mdes
|
170
185
|
|
171
186
|
##
|
187
|
+
# Returns the module namespacing the models for the active MDES version.
|
188
|
+
#
|
189
|
+
# N.b.: this method triggers loading the default MDES module and
|
190
|
+
# specification if {#mdes_version=} has not been called yet.
|
191
|
+
#
|
172
192
|
# @return [Module] the module namespacing the models for the
|
173
193
|
# active MDES version.
|
174
194
|
def models_module
|
@@ -274,8 +274,10 @@ module NcsNavigator::Warehouse::Transformers
|
|
274
274
|
# @param [Symbol] name the name of this producer; if you don't
|
275
275
|
# specify a `:query`, the default is to return every row from
|
276
276
|
# the application table with this name.
|
277
|
-
# @param [Class]
|
278
|
-
# the query will be mapped.
|
277
|
+
# @param [Class,Symbol] model_or_reference the warehouse model to which
|
278
|
+
# the results of the query will be mapped. It can be expressed either
|
279
|
+
# as the model class itself or the unqualified name of the model. (See
|
280
|
+
# {Configuration#model}.)
|
279
281
|
# @param [Hash] options
|
280
282
|
# @option options :query [String] the query to execute for this
|
281
283
|
# producer. If not specified, the query is `"SELECT * FROM #{name}"`.
|
@@ -292,13 +294,13 @@ module NcsNavigator::Warehouse::Transformers
|
|
292
294
|
# column map don't match them to anything.
|
293
295
|
#
|
294
296
|
# @return [void]
|
295
|
-
def produce_one_for_one(name,
|
297
|
+
def produce_one_for_one(name, model_or_reference, options={})
|
296
298
|
options[:column_map] =
|
297
299
|
(options[:column_map] || {}).inject({}) { |h, (k, v)| h[k.to_s] = v.to_s; h }
|
298
300
|
options[:ignored_columns] = (options[:ignored_columns] || []).collect(&:to_s)
|
299
301
|
|
300
302
|
record_producers <<
|
301
|
-
OneForOneProducer.new(name, options.delete(:query),
|
303
|
+
OneForOneProducer.new(name, options.delete(:query), model_or_reference, self, options)
|
302
304
|
end
|
303
305
|
end
|
304
306
|
|
@@ -313,11 +315,11 @@ module NcsNavigator::Warehouse::Transformers
|
|
313
315
|
##
|
314
316
|
# The class encapsulating one call to {DSL#produce_one_for_one}
|
315
317
|
class OneForOneProducer < RecordProducer
|
316
|
-
attr_reader :
|
318
|
+
attr_reader :model_or_reference, :options, :dsl_host
|
317
319
|
|
318
|
-
def initialize(name, query,
|
320
|
+
def initialize(name, query, model_or_reference, dsl_host, options)
|
319
321
|
super(name, query, self)
|
320
|
-
@
|
322
|
+
@model_or_reference = model_or_reference
|
321
323
|
@dsl_host = dsl_host
|
322
324
|
@options = options
|
323
325
|
end
|
@@ -325,14 +327,14 @@ module NcsNavigator::Warehouse::Transformers
|
|
325
327
|
##
|
326
328
|
# Produces a single instance of {#model} using the values in the
|
327
329
|
# row as mapped by {#column_map}.
|
328
|
-
def convert_row(row)
|
329
|
-
col_map = column_map(row.members)
|
330
|
+
def convert_row(row, meta)
|
331
|
+
col_map = column_map(row.members, meta[:configuration])
|
330
332
|
unused = row.members.collect(&:to_s) - col_map.keys - ignored_columns
|
331
333
|
|
332
334
|
if on_unused == :fail && !unused.empty?
|
333
335
|
raise UnusedColumnsForModelError.new(unused)
|
334
336
|
end
|
335
|
-
model.new(
|
337
|
+
model(meta[:configuration]).new(
|
336
338
|
col_map.inject({}) { |pv, (col_name, var_name)|
|
337
339
|
pv[var_name] = clean_value(row[col_name]);
|
338
340
|
pv
|
@@ -343,7 +345,23 @@ module NcsNavigator::Warehouse::Transformers
|
|
343
345
|
|
344
346
|
##
|
345
347
|
# Implemented so that this class behaves like a lambda.
|
346
|
-
def arity;
|
348
|
+
def arity; 2; end
|
349
|
+
|
350
|
+
##
|
351
|
+
# @param configuration [Configuration]
|
352
|
+
#
|
353
|
+
# @return [Class] the model for this producer. If {#model_or_reference}
|
354
|
+
# is a symbolic reference, this method resolves it using the given
|
355
|
+
# configuration.
|
356
|
+
def model(configuration)
|
357
|
+
case model_or_reference
|
358
|
+
when Class
|
359
|
+
model_or_reference
|
360
|
+
else
|
361
|
+
configuration.model(model_or_reference) or
|
362
|
+
fail("There is no table or model named #{model_or_reference.inspect} in MDES #{configuration.mdes_version}.")
|
363
|
+
end
|
364
|
+
end
|
347
365
|
|
348
366
|
def clean_value(v)
|
349
367
|
if v.respond_to?(:strip)
|
@@ -356,12 +374,15 @@ module NcsNavigator::Warehouse::Transformers
|
|
356
374
|
|
357
375
|
##
|
358
376
|
# @param [Array<String>] column_names
|
377
|
+
# @param [Configuration] configuration the configuration to use to resolve
|
378
|
+
# model references, if necessary.
|
379
|
+
#
|
359
380
|
# @return [Hash<String, String>] a mapping from the given
|
360
381
|
# column names to MDES variable names for the configured
|
361
382
|
# model. This mapping reflects both the configured explicit
|
362
383
|
# mapping and the heuristic.
|
363
|
-
def column_map(column_names)
|
364
|
-
available_props = model.properties.collect { |p| p.name.to_s }
|
384
|
+
def column_map(column_names, configuration)
|
385
|
+
available_props = model(configuration).properties.collect { |p| p.name.to_s }
|
365
386
|
available_props -= options[:column_map].values
|
366
387
|
|
367
388
|
column_names.inject(options[:column_map].dup) do |map, column|
|
@@ -124,6 +124,12 @@ module NcsNavigator::Warehouse
|
|
124
124
|
end
|
125
125
|
end
|
126
126
|
|
127
|
+
describe '#mdes_version', :slow, :use_mdes, :modifies_warehouse_state do
|
128
|
+
it 'is a shortcut for extracting the version from #mdes' do
|
129
|
+
spec_config.mdes_version.should == spec_mdes_version
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
127
133
|
describe '#mdes', :slow, :modifies_warehouse_state do
|
128
134
|
it 'Uses the default MDES version if called before mdes_version=' do
|
129
135
|
config.mdes.version.should == NcsNavigator::Warehouse::DEFAULT_MDES_VERSION
|
@@ -273,6 +273,7 @@ module NcsNavigator::Warehouse::Transformers
|
|
273
273
|
let(:options) { {} }
|
274
274
|
let(:cls) { sample_class }
|
275
275
|
let(:producer) { cls.record_producers.first }
|
276
|
+
let(:row_meta) { {} }
|
276
277
|
|
277
278
|
def make_row(contents)
|
278
279
|
Struct.new(*contents.keys).new.tap do |r|
|
@@ -284,7 +285,7 @@ module NcsNavigator::Warehouse::Transformers
|
|
284
285
|
|
285
286
|
def model_row(row)
|
286
287
|
cls.produce_one_for_one(:addresses, address_model, options)
|
287
|
-
producer.row_processor.call(make_row(row))
|
288
|
+
producer.row_processor.call(make_row(row), row_meta)
|
288
289
|
end
|
289
290
|
|
290
291
|
it 'maps a column to the property with the same name' do
|
@@ -314,6 +315,36 @@ module NcsNavigator::Warehouse::Transformers
|
|
314
315
|
# expect no errors
|
315
316
|
end
|
316
317
|
|
318
|
+
describe 'and a symbolic model' do
|
319
|
+
let(:address_model) { :Address }
|
320
|
+
let(:mock_config) { mock('Configuration') }
|
321
|
+
|
322
|
+
before do
|
323
|
+
row_meta[:configuration] = mock_config
|
324
|
+
mock_config.stub!(:model).and_return(Database::DSL::TestModels::Address)
|
325
|
+
end
|
326
|
+
|
327
|
+
it 'resolves the model using the configuration' do
|
328
|
+
mock_config.should_receive(:model).with(address_model).and_return(Database::DSL::TestModels::Address)
|
329
|
+
|
330
|
+
model_row(:street => '42 Foo').street.should == '42 Foo'
|
331
|
+
end
|
332
|
+
|
333
|
+
it 'throws an exception if the model does not exist' do
|
334
|
+
mock_config.should_receive(:model).with(address_model).and_return(nil)
|
335
|
+
mock_config.stub!(:mdes_version).and_return('3.4')
|
336
|
+
|
337
|
+
expect { model_row(:street => '42 Baz') }.
|
338
|
+
to raise_error('There is no table or model named :Address in MDES 3.4.')
|
339
|
+
end
|
340
|
+
|
341
|
+
it 'can retrieve the column map' do
|
342
|
+
options[:column_map] = { :street_loc => :street }
|
343
|
+
cls.produce_one_for_one(:addresses, address_model, options)
|
344
|
+
producer.column_map(%w(street street_loc), mock_config).keys.should == %w(street_loc)
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
317
348
|
describe 'and unused columns' do
|
318
349
|
it 'fails with unused columns if requested' do
|
319
350
|
options[:on_unused] = :fail
|
@@ -349,7 +380,7 @@ module NcsNavigator::Warehouse::Transformers
|
|
349
380
|
|
350
381
|
it 'fails appropriately' do
|
351
382
|
begin
|
352
|
-
producer.call(make_row
|
383
|
+
producer.call(make_row(:address_type => '-5', :address_length => '6'), row_meta)
|
353
384
|
fail "Exception not thrown"
|
354
385
|
rescue Database::UnusedColumnsForModelError => e
|
355
386
|
e.unused.should == %w(address_length)
|
@@ -358,13 +389,13 @@ module NcsNavigator::Warehouse::Transformers
|
|
358
389
|
|
359
390
|
it 'does not fail if the global setting is overridden' do
|
360
391
|
options[:on_unused] = :ignore
|
361
|
-
lambda { producer.call(make_row
|
392
|
+
lambda { producer.call(make_row(:address_type => '-5', :address_length => '6'), row_meta) }.
|
362
393
|
should_not raise_error
|
363
394
|
end
|
364
395
|
|
365
396
|
it 'can be ignored by modifying the global setting' do
|
366
397
|
cls.on_unused_columns :ignore
|
367
|
-
lambda { producer.call(make_row
|
398
|
+
lambda { producer.call(make_row(:address_type => '-5', :address_length => '6'), row_meta) }.
|
368
399
|
should_not raise_error
|
369
400
|
end
|
370
401
|
end
|
@@ -405,19 +436,19 @@ module NcsNavigator::Warehouse::Transformers
|
|
405
436
|
|
406
437
|
it 'does not include the default mapping in the total map' do
|
407
438
|
cls.produce_one_for_one(:addresses, address_model, options)
|
408
|
-
producer.column_map(%w(street street_loc)).keys.should == %w(street_loc)
|
439
|
+
producer.column_map(%w(street street_loc), configuration).keys.should == %w(street_loc)
|
409
440
|
end
|
410
441
|
|
411
442
|
it 'always includes explicit mapping values in the total map' do
|
412
443
|
cls.produce_one_for_one(:addresses, address_model, options)
|
413
|
-
producer.column_map(%w(street)).keys.should == %w(street_loc)
|
444
|
+
producer.column_map(%w(street), configuration).keys.should == %w(street_loc)
|
414
445
|
end
|
415
446
|
end
|
416
447
|
|
417
448
|
describe 'the processor' do
|
418
449
|
it 'responds to :arity' do
|
419
450
|
cls.produce_one_for_one(:addresses, address_model, options)
|
420
|
-
producer.row_processor.arity.should ==
|
451
|
+
producer.row_processor.arity.should == 2
|
421
452
|
end
|
422
453
|
end
|
423
454
|
end
|
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.
|
4
|
+
version: 0.9.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-10-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ncs_mdes
|
@@ -2379,12 +2379,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
2379
2379
|
- - ! '>='
|
2380
2380
|
- !ruby/object:Gem::Version
|
2381
2381
|
version: '0'
|
2382
|
+
segments:
|
2383
|
+
- 0
|
2384
|
+
hash: -1614550889051803335
|
2382
2385
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
2383
2386
|
none: false
|
2384
2387
|
requirements:
|
2385
2388
|
- - ! '>='
|
2386
2389
|
- !ruby/object:Gem::Version
|
2387
2390
|
version: '0'
|
2391
|
+
segments:
|
2392
|
+
- 0
|
2393
|
+
hash: -1614550889051803335
|
2388
2394
|
requirements: []
|
2389
2395
|
rubyforge_project:
|
2390
2396
|
rubygems_version: 1.8.24
|