hqmf-parser 1.0.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/Gemfile +23 -0
- data/README.md +903 -0
- data/Rakefile +19 -0
- data/VERSION +1 -0
- data/lib/hqmf-generator/hqmf-generator.rb +308 -0
- data/lib/hqmf-model/attribute.rb +35 -0
- data/lib/hqmf-model/data_criteria.rb +322 -0
- data/lib/hqmf-model/document.rb +172 -0
- data/lib/hqmf-model/population_criteria.rb +90 -0
- data/lib/hqmf-model/precondition.rb +85 -0
- data/lib/hqmf-model/types.rb +318 -0
- data/lib/hqmf-model/utilities.rb +52 -0
- data/lib/hqmf-parser.rb +54 -0
- data/lib/hqmf-parser/1.0/attribute.rb +68 -0
- data/lib/hqmf-parser/1.0/comparison.rb +34 -0
- data/lib/hqmf-parser/1.0/data_criteria.rb +105 -0
- data/lib/hqmf-parser/1.0/document.rb +209 -0
- data/lib/hqmf-parser/1.0/expression.rb +52 -0
- data/lib/hqmf-parser/1.0/population_criteria.rb +79 -0
- data/lib/hqmf-parser/1.0/precondition.rb +89 -0
- data/lib/hqmf-parser/1.0/range.rb +65 -0
- data/lib/hqmf-parser/1.0/restriction.rb +157 -0
- data/lib/hqmf-parser/1.0/utilities.rb +41 -0
- data/lib/hqmf-parser/2.0/data_criteria.rb +319 -0
- data/lib/hqmf-parser/2.0/document.rb +165 -0
- data/lib/hqmf-parser/2.0/population_criteria.rb +53 -0
- data/lib/hqmf-parser/2.0/precondition.rb +44 -0
- data/lib/hqmf-parser/2.0/types.rb +223 -0
- data/lib/hqmf-parser/2.0/utilities.rb +30 -0
- data/lib/hqmf-parser/converter/pass1/data_criteria_converter.rb +254 -0
- data/lib/hqmf-parser/converter/pass1/document_converter.rb +183 -0
- data/lib/hqmf-parser/converter/pass1/population_criteria_converter.rb +135 -0
- data/lib/hqmf-parser/converter/pass1/precondition_converter.rb +164 -0
- data/lib/hqmf-parser/converter/pass1/precondition_extractor.rb +159 -0
- data/lib/hqmf-parser/converter/pass1/simple_data_criteria.rb +35 -0
- data/lib/hqmf-parser/converter/pass1/simple_operator.rb +89 -0
- data/lib/hqmf-parser/converter/pass1/simple_population_criteria.rb +10 -0
- data/lib/hqmf-parser/converter/pass1/simple_precondition.rb +63 -0
- data/lib/hqmf-parser/converter/pass1/simple_restriction.rb +64 -0
- data/lib/hqmf-parser/converter/pass2/comparison_converter.rb +91 -0
- data/lib/hqmf-parser/converter/pass2/operator_converter.rb +169 -0
- data/lib/hqmf-parser/converter/pass3/specific_occurrence_converter.rb +86 -0
- data/lib/hqmf-parser/converter/pass3/specific_occurrence_converter_bak.rb +70 -0
- data/lib/hqmf-parser/parser.rb +22 -0
- data/lib/hqmf-parser/value_sets/value_set_parser.rb +206 -0
- data/lib/tasks/coverme.rake +8 -0
- data/lib/tasks/hqmf.rake +141 -0
- data/lib/tasks/value_sets.rake +23 -0
- metadata +159 -0
@@ -0,0 +1,183 @@
|
|
1
|
+
module HQMF
|
2
|
+
# Class for converting an HQMF 1.0 representation to an HQMF 2.0 representation
|
3
|
+
class DocumentConverter
|
4
|
+
|
5
|
+
BIRTHTIME_CODE_LIST = {'LOINC'=>['21112-8']}
|
6
|
+
|
7
|
+
def self.convert(json, codes)
|
8
|
+
|
9
|
+
title = json[:title]
|
10
|
+
description = json[:description]
|
11
|
+
|
12
|
+
metadata = json[:metadata]
|
13
|
+
metadata.keys.each {|key| metadata[key.to_s] = metadata[key]; metadata.delete(key.to_sym)}
|
14
|
+
|
15
|
+
id = metadata["NQF_ID_NUMBER"][:value] if metadata["NQF_ID_NUMBER"]
|
16
|
+
attributes = parse_attributes(metadata)
|
17
|
+
hqmf_id = json[:hqmf_id]
|
18
|
+
hqmf_set_id = json[:hqmf_set_id]
|
19
|
+
hqmf_version_number = json[:hqmf_version_number]
|
20
|
+
|
21
|
+
measure_period = parse_measure_period(json)
|
22
|
+
@data_criteria_converter = DataCriteriaConverter.new(json, measure_period)
|
23
|
+
|
24
|
+
# source data criteria are the original unmodified v2 data criteria
|
25
|
+
source_data_criteria = []
|
26
|
+
@data_criteria_converter.v2_data_criteria.each {|criteria| source_data_criteria << criteria}
|
27
|
+
|
28
|
+
# PASS 1
|
29
|
+
@population_criteria_converter = PopulationCriteriaConverter.new(json, @data_criteria_converter)
|
30
|
+
population_criteria = @population_criteria_converter.population_criteria
|
31
|
+
|
32
|
+
# PASS 2
|
33
|
+
comparison_converter = HQMF::ComparisonConverter.new(@data_criteria_converter)
|
34
|
+
comparison_converter.convert_comparisons(population_criteria)
|
35
|
+
|
36
|
+
# PASS 3
|
37
|
+
# specific_occurrence_converter = HQMF::SpecificOccurrenceConverter.new(@data_criteria_converter)
|
38
|
+
# specific_occurrence_converter.convert_specific_occurrences(population_criteria)
|
39
|
+
|
40
|
+
data_criteria = @data_criteria_converter.final_v2_data_criteria
|
41
|
+
|
42
|
+
populations = @population_criteria_converter.sub_measures
|
43
|
+
|
44
|
+
doc = HQMF::Document.new(id, hqmf_id, hqmf_set_id, hqmf_version_number, title, description, population_criteria, data_criteria, source_data_criteria, attributes, measure_period, populations)
|
45
|
+
|
46
|
+
backfill_patient_characteristics_with_codes(doc, codes)
|
47
|
+
|
48
|
+
HQMF::DocumentConverter.validate(doc, codes)
|
49
|
+
|
50
|
+
doc
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def self.parse_attributes(metadata)
|
57
|
+
attributes = []
|
58
|
+
metadata.keys.each do |key|
|
59
|
+
attribute_hash = metadata[key]
|
60
|
+
code = attribute_hash[:code]
|
61
|
+
value = attribute_hash[:value]
|
62
|
+
unit = attribute_hash[:unit]
|
63
|
+
name = attribute_hash[:name]
|
64
|
+
attributes << HQMF::Attribute.new(key,code,value,unit,name)
|
65
|
+
end
|
66
|
+
attributes
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
# patient characteristics data criteria such as GENDER require looking at the codes to determine if the
|
71
|
+
# measure is interested in Males or Females. This process is awkward, and thus is done as a separate
|
72
|
+
# step after the document has been converted.
|
73
|
+
def self.backfill_patient_characteristics_with_codes(doc, codes)
|
74
|
+
|
75
|
+
[].concat(doc.all_data_criteria).concat(doc.source_data_criteria).each do |data_criteria|
|
76
|
+
if (data_criteria.type == :characteristic and !data_criteria.property.nil?)
|
77
|
+
if (codes)
|
78
|
+
value_set = codes[data_criteria.code_list_id]
|
79
|
+
puts "\tno value set for unknown patient characteristic: #{data_criteria.id}" unless value_set
|
80
|
+
else
|
81
|
+
puts "\tno code set to back fill: #{data_criteria.title}"
|
82
|
+
next
|
83
|
+
end
|
84
|
+
|
85
|
+
if (data_criteria.property == :gender)
|
86
|
+
key = value_set.keys[0]
|
87
|
+
data_criteria.value = HQMF::Coded.new('CD','Administrative Sex',value_set[key].first)
|
88
|
+
else
|
89
|
+
data_criteria.inline_code_list = value_set
|
90
|
+
end
|
91
|
+
|
92
|
+
elsif (data_criteria.type == :characteristic)
|
93
|
+
if (codes)
|
94
|
+
value_set = codes[data_criteria.code_list_id]
|
95
|
+
if (value_set)
|
96
|
+
# this is looking for a birthdate characteristic that is set as a generic characteristic but points to a loinc code set
|
97
|
+
if (value_set['LOINC'] and value_set['LOINC'].first == '21112-8')
|
98
|
+
data_criteria.definition = 'patient_characteristic_birthdate'
|
99
|
+
end
|
100
|
+
# this is looking for a gender characteristic that is set as a generic characteristic
|
101
|
+
gender_key = (value_set.keys.select {|set| set.start_with? 'HL7'}).first
|
102
|
+
if (gender_key and ['M','F'].include? value_set[gender_key].first)
|
103
|
+
data_criteria.definition = 'patient_characteristic_gender'
|
104
|
+
data_criteria.value = HQMF::Coded.new('CD','Gender',value_set[gender_key].first)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
def self.parse_measure_period(json)
|
115
|
+
|
116
|
+
# Create a new HQMF::EffectiveTime
|
117
|
+
# @param [Value] low
|
118
|
+
# @param [Value] high
|
119
|
+
# @param [Value] width
|
120
|
+
# ----------
|
121
|
+
# Create a new HQMF::Value
|
122
|
+
# @param [String] type
|
123
|
+
# @param [String] unit
|
124
|
+
# @param [String] value
|
125
|
+
# @param [String] inclusive
|
126
|
+
# @param [String] derived
|
127
|
+
# @param [String] expression
|
128
|
+
|
129
|
+
low = HQMF::Value.new('TS',nil,'20100101',nil, nil, nil)
|
130
|
+
high = HQMF::Value.new('TS',nil,'20110101',nil, nil, nil)
|
131
|
+
width = HQMF::Value.new('PQ','a','1',nil, nil, nil)
|
132
|
+
|
133
|
+
# puts ('need to figure out a way to make dates dynamic')
|
134
|
+
|
135
|
+
HQMF::EffectiveTime.new(low,high,width)
|
136
|
+
end
|
137
|
+
|
138
|
+
def self.validate(document,codes)
|
139
|
+
puts "\t(#{document.id})document is nil!!!!!!!!!!!" unless document
|
140
|
+
puts "\t(#{document.id})codes are nil!!!!!!!!!!!" unless codes
|
141
|
+
return unless document and codes
|
142
|
+
|
143
|
+
referenced_oids = document.all_data_criteria.map(&:code_list_id).compact.uniq
|
144
|
+
|
145
|
+
referenced_oids.each do |oid|
|
146
|
+
value_set = codes[oid]
|
147
|
+
puts "\tDC (#{document.id},#{document.title}): referenced OID could not be found #{oid}" unless value_set
|
148
|
+
end
|
149
|
+
|
150
|
+
oid_values = document.all_data_criteria.select {|dc| dc.value != nil and dc.value.type == 'CD'}
|
151
|
+
|
152
|
+
if oid_values.size > 0
|
153
|
+
referenced_oids = (oid_values.map {|dc| dc.value.code_list_id }).compact.uniq
|
154
|
+
referenced_oids.each do |oid|
|
155
|
+
value_set = codes[oid]
|
156
|
+
puts "\tVALUE (#{document.id},#{document.title}): referenced OID could not be found #{oid}" unless value_set
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
oid_negation = document.all_data_criteria.select {|dc| dc.negation_code_list_id != nil}
|
162
|
+
if oid_negation.size > 0
|
163
|
+
referenced_oids = (oid_negation.map {|dc| dc.negation_code_list_id}).compact.uniq
|
164
|
+
referenced_oids.each do |oid|
|
165
|
+
value_set = codes[oid]
|
166
|
+
puts "\tNEGATION (#{document.id},#{document.title}): referenced OID could not be found #{oid}" unless value_set
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
oid_fields = document.all_data_criteria.select {|dc| dc.field_values != nil}
|
171
|
+
if oid_fields.size > 0
|
172
|
+
referenced_oids = (oid_fields.map{|dc| dc.field_values.map {|key,field| puts "field: #{key} is nil" unless field; field.code_list_id if field != nil and field.type == 'CD'}}).flatten.compact.uniq
|
173
|
+
referenced_oids.each do |oid|
|
174
|
+
value_set = codes[oid]
|
175
|
+
puts "\tFIELDS (#{document.id},#{document.title}): referenced OID could not be found #{oid}" unless value_set
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
|
182
|
+
end
|
183
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
module HQMF
|
2
|
+
# Class for converting an HQMF 1.0 representation to an HQMF 2.0 representation
|
3
|
+
class PopulationCriteriaConverter
|
4
|
+
|
5
|
+
attr_reader :sub_measures
|
6
|
+
|
7
|
+
def initialize(doc, data_criteria_converter)
|
8
|
+
@doc = doc
|
9
|
+
@data_criteria_converter = data_criteria_converter
|
10
|
+
@population_criteria_by_id = {}
|
11
|
+
@population_criteria_by_key = {}
|
12
|
+
@population_reference = {}
|
13
|
+
parse()
|
14
|
+
build_sub_measures()
|
15
|
+
end
|
16
|
+
|
17
|
+
def population_criteria
|
18
|
+
@population_criteria_by_key.values
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def build_sub_measures()
|
24
|
+
@sub_measures = []
|
25
|
+
ipps = @population_criteria_by_id.select {|key, value| value.type == HQMF::PopulationCriteria::IPP}
|
26
|
+
denoms = @population_criteria_by_id.select {|key, value| value.type == HQMF::PopulationCriteria::DENOM}
|
27
|
+
nums = @population_criteria_by_id.select {|key, value| value.type == HQMF::PopulationCriteria::NUMER}
|
28
|
+
excls = @population_criteria_by_id.select {|key, value| value.type == HQMF::PopulationCriteria::DENEX}
|
29
|
+
denexcs = @population_criteria_by_id.select {|key, value| value.type == HQMF::PopulationCriteria::EXCEP}
|
30
|
+
|
31
|
+
if (ipps.size<=1 and denoms.size<=1 and nums.size<=1 and excls.size<=1 and denexcs.size<=1 )
|
32
|
+
@sub_measures <<
|
33
|
+
{
|
34
|
+
HQMF::PopulationCriteria::IPP => HQMF::PopulationCriteria::IPP,
|
35
|
+
HQMF::PopulationCriteria::DENOM => HQMF::PopulationCriteria::DENOM,
|
36
|
+
HQMF::PopulationCriteria::NUMER => HQMF::PopulationCriteria::NUMER,
|
37
|
+
HQMF::PopulationCriteria::EXCEP => HQMF::PopulationCriteria::EXCEP,
|
38
|
+
HQMF::PopulationCriteria::DENEX => HQMF::PopulationCriteria::DENEX
|
39
|
+
}
|
40
|
+
else
|
41
|
+
|
42
|
+
nums.each do |num_id, num|
|
43
|
+
@sub_measures << {HQMF::PopulationCriteria::NUMER => num.id}
|
44
|
+
end
|
45
|
+
apply_to_submeasures(@sub_measures, HQMF::PopulationCriteria::DENOM, denoms.values)
|
46
|
+
apply_to_submeasures(@sub_measures, HQMF::PopulationCriteria::IPP, ipps.values)
|
47
|
+
apply_to_submeasures(@sub_measures, HQMF::PopulationCriteria::DENEX, excls.values)
|
48
|
+
apply_to_submeasures(@sub_measures, HQMF::PopulationCriteria::EXCEP, denexcs.values)
|
49
|
+
|
50
|
+
keep = []
|
51
|
+
@sub_measures.each do |sub|
|
52
|
+
|
53
|
+
value = sub
|
54
|
+
HQMF::PopulationCriteria::ALL_POPULATION_CODES.each do |type|
|
55
|
+
key = sub[type]
|
56
|
+
if (key)
|
57
|
+
reference_id = @population_reference[key]
|
58
|
+
reference = @population_criteria_by_id[reference_id] if reference_id
|
59
|
+
if (reference)
|
60
|
+
criteria = @population_criteria_by_key[sub[reference.type]]
|
61
|
+
value['stratification'] = criteria.stratification_id if criteria.stratification_id
|
62
|
+
value = nil if (sub[reference.type] != reference.id and criteria.stratification_id.nil?)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
keep << value if (value)
|
67
|
+
end
|
68
|
+
|
69
|
+
keep.each_with_index do |sub, i|
|
70
|
+
sub['title'] = "Population #{i+1}"
|
71
|
+
sub['id'] = "Population#{i+1}"
|
72
|
+
end
|
73
|
+
|
74
|
+
@sub_measures = keep
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def apply_to_submeasures(subs, type, values)
|
80
|
+
new_subs = []
|
81
|
+
subs.each do |sub|
|
82
|
+
values.each do |value|
|
83
|
+
if (sub[type] and sub[type] != value.id)
|
84
|
+
tmp = {}
|
85
|
+
HQMF::PopulationCriteria::ALL_POPULATION_CODES.each do |key|
|
86
|
+
tmp[key] = sub[key] if sub[key]
|
87
|
+
end
|
88
|
+
sub = tmp
|
89
|
+
new_subs << sub
|
90
|
+
end
|
91
|
+
sub[type] = value.id
|
92
|
+
end
|
93
|
+
end
|
94
|
+
subs.concat(new_subs)
|
95
|
+
end
|
96
|
+
|
97
|
+
def find_sub_measures(type, value)
|
98
|
+
found = []
|
99
|
+
@sub_measures.each do |sub_measure|
|
100
|
+
found << sub_measure if sub_measure[type] and sub_measure[type] == value.id
|
101
|
+
end
|
102
|
+
found
|
103
|
+
end
|
104
|
+
|
105
|
+
def parse()
|
106
|
+
@doc[:logic].each do |key,criteria|
|
107
|
+
@population_criteria_by_key[key] = convert(key.to_s, criteria)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def convert(key, population_criteria)
|
112
|
+
|
113
|
+
# @param [String] id
|
114
|
+
# @param [Array#Precondition] preconditions
|
115
|
+
|
116
|
+
preconditions = HQMF::PreconditionConverter.parse_preconditions(population_criteria[:preconditions],@data_criteria_converter)
|
117
|
+
hqmf_id = population_criteria[:hqmf_id] || population_criteria[:id]
|
118
|
+
id = population_criteria[:id]
|
119
|
+
type = population_criteria[:code]
|
120
|
+
reference = population_criteria[:reference]
|
121
|
+
title = population_criteria[:title]
|
122
|
+
|
123
|
+
criteria = HQMF::Converter::SimplePopulationCriteria.new(key, hqmf_id, type, preconditions, title)
|
124
|
+
# mark the 2.0 simple population criteria as a stratification... this allows us to create the cartesian product for this in the populations
|
125
|
+
criteria.stratification_id = population_criteria[:stratification_id]
|
126
|
+
|
127
|
+
@population_criteria_by_id[id] = criteria
|
128
|
+
@population_reference[key] = reference
|
129
|
+
|
130
|
+
criteria
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
module HQMF
|
2
|
+
# Class for converting an HQMF 1.0 representation to an HQMF 2.0 representation
|
3
|
+
class PreconditionConverter
|
4
|
+
|
5
|
+
def self.parse_preconditions(source,data_criteria_converter)
|
6
|
+
|
7
|
+
# preconditions = []
|
8
|
+
# source.each do |precondition|
|
9
|
+
# preconditions << HQMF::PreconditionConverter.parse_precondition(precondition,data_criteria_converter)
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# preconditions
|
13
|
+
|
14
|
+
parse_and_merge_preconditions(source,data_criteria_converter)
|
15
|
+
end
|
16
|
+
|
17
|
+
# converts a precondtion to a hqmf model
|
18
|
+
def self.parse_precondition(precondition,data_criteria_converter)
|
19
|
+
|
20
|
+
# grab child preconditions, and parse recursively
|
21
|
+
preconditions = parse_and_merge_preconditions(precondition[:preconditions],data_criteria_converter) if precondition[:preconditions] || []
|
22
|
+
|
23
|
+
preconditions_from_restrictions = HQMF::PreconditionExtractor.extract_preconditions_from_restrictions(precondition[:restrictions], data_criteria_converter)
|
24
|
+
|
25
|
+
# driv preconditions are preconditions that are the children of an expression
|
26
|
+
driv_preconditions = []
|
27
|
+
preconditions_from_restrictions.delete_if {|element| driv_preconditions << element if element.is_a? HQMF::Converter::SimpleRestriction and element.operator.type == 'DRIV'}
|
28
|
+
|
29
|
+
apply_restrictions_to_comparisons(preconditions, preconditions_from_restrictions) unless preconditions_from_restrictions.empty?
|
30
|
+
|
31
|
+
conjunction_code = convert_logical_conjunction(precondition[:conjunction])
|
32
|
+
|
33
|
+
if (precondition[:expression])
|
34
|
+
# this is for things like COUNT
|
35
|
+
type = precondition[:expression][:type]
|
36
|
+
operator = HQMF::Converter::SimpleOperator.new(HQMF::Converter::SimpleOperator.find_category(type), type, HQMF::Converter::SimpleOperator.parse_value(precondition[:expression][:value]))
|
37
|
+
children = []
|
38
|
+
if driv_preconditions and !driv_preconditions.empty?
|
39
|
+
children = driv_preconditions.map(&:preconditions).flatten
|
40
|
+
end
|
41
|
+
|
42
|
+
reference = nil
|
43
|
+
# take the conjunction code from the parent precondition
|
44
|
+
|
45
|
+
restriction = HQMF::Converter::SimpleRestriction.new(operator, nil, children)
|
46
|
+
|
47
|
+
comparison_precondition = HQMF::Converter::SimplePrecondition.new(nil,[restriction],reference,conjunction_code, false)
|
48
|
+
comparison_precondition.klass = HQMF::Converter::SimplePrecondition::COMPARISON
|
49
|
+
comparison_precondition.subset_comparison = true
|
50
|
+
preconditions << comparison_precondition
|
51
|
+
end
|
52
|
+
|
53
|
+
reference = nil
|
54
|
+
|
55
|
+
negation = precondition[:negation]
|
56
|
+
|
57
|
+
|
58
|
+
if (precondition[:comparison])
|
59
|
+
preconditions ||= []
|
60
|
+
comparison_precondition = HQMF::PreconditionExtractor.convert_comparison_to_precondition(precondition[:comparison],data_criteria_converter)
|
61
|
+
preconditions << comparison_precondition
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
if (precondition[:subset])
|
66
|
+
# this is for things like FIRST on preconditions
|
67
|
+
type = precondition[:subset]
|
68
|
+
operator = HQMF::Converter::SimpleOperator.new(HQMF::Converter::SimpleOperator.find_category(type), type, nil)
|
69
|
+
children = preconditions
|
70
|
+
|
71
|
+
reference = nil
|
72
|
+
# take the conjunction code from the parent precondition
|
73
|
+
|
74
|
+
restriction = HQMF::Converter::SimpleRestriction.new(operator, nil, children)
|
75
|
+
|
76
|
+
comparison_precondition = HQMF::Converter::SimplePrecondition.new(nil,[restriction],reference,conjunction_code, false)
|
77
|
+
comparison_precondition.klass = HQMF::Converter::SimplePrecondition::COMPARISON
|
78
|
+
preconditions = [comparison_precondition]
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
HQMF::Converter::SimplePrecondition.new(nil,preconditions,reference,conjunction_code, negation)
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.get_comparison_preconditions(preconditions)
|
87
|
+
comparisons = []
|
88
|
+
preconditions.each do |precondition|
|
89
|
+
if (precondition.comparison? and !precondition.subset_comparison)
|
90
|
+
comparisons << precondition
|
91
|
+
elsif(precondition.has_preconditions?)
|
92
|
+
comparisons.concat(get_comparison_preconditions(precondition.preconditions))
|
93
|
+
else
|
94
|
+
raise "precondition with no comparison or children... not valid"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
comparisons
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.apply_restrictions_to_comparisons(preconditions, restrictions)
|
101
|
+
comparisons = get_comparison_preconditions(preconditions)
|
102
|
+
raise "no comparisons to apply restriction to" if comparisons.empty?
|
103
|
+
comparisons.each do |comparison|
|
104
|
+
comparison.preconditions.concat(restrictions)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
|
111
|
+
def self.parse_and_merge_preconditions(source,data_criteria_converter)
|
112
|
+
return [] unless source and source.size > 0
|
113
|
+
preconditions_by_conjunction = {}
|
114
|
+
source.each do |precondition|
|
115
|
+
parsed = HQMF::PreconditionConverter.parse_precondition(precondition,data_criteria_converter)
|
116
|
+
preconditions_by_conjunction[parsed.conjunction_code] ||= []
|
117
|
+
preconditions_by_conjunction[parsed.conjunction_code] << parsed
|
118
|
+
end
|
119
|
+
|
120
|
+
merge_precondtion_conjunction_groups(preconditions_by_conjunction)
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.merge_precondtion_conjunction_groups(preconditions_by_conjunction)
|
124
|
+
joined = []
|
125
|
+
preconditions_by_conjunction.each do |conjunction_code, preconditions|
|
126
|
+
sub_conditions = []
|
127
|
+
negated_conditions = []
|
128
|
+
preconditions.each do |precondition|
|
129
|
+
unless (precondition.negation)
|
130
|
+
sub_conditions.concat precondition.preconditions if precondition.preconditions
|
131
|
+
else
|
132
|
+
negated_conditions.concat precondition.preconditions if precondition.preconditions
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
if (!sub_conditions.empty?)
|
137
|
+
# if we have negated conditions, add them to a new precondition of the same conjunction that is negated
|
138
|
+
if (!negated_conditions.empty?)
|
139
|
+
sub_conditions << HQMF::Converter::SimplePrecondition.new(nil,negated_conditions,nil,conjunction_code, true)
|
140
|
+
end
|
141
|
+
joined << HQMF::Converter::SimplePrecondition.new(nil,sub_conditions,nil,conjunction_code, false)
|
142
|
+
elsif (!negated_conditions.empty?)
|
143
|
+
joined << HQMF::Converter::SimplePrecondition.new(nil,negated_conditions,nil,conjunction_code, true)
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
joined
|
148
|
+
end
|
149
|
+
|
150
|
+
def self.convert_logical_conjunction(code)
|
151
|
+
case code
|
152
|
+
when 'OR'
|
153
|
+
HQMF::Precondition::AT_LEAST_ONE_TRUE
|
154
|
+
when 'AND'
|
155
|
+
HQMF::Precondition::ALL_TRUE
|
156
|
+
else
|
157
|
+
raise "unsupported logical conjunction code conversion: #{code}"
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
end
|
164
|
+
end
|