hqmf2js 1.3.0 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/.travis.yml +1 -1
- data/Gemfile +1 -25
- data/Gemfile.lock +170 -146
- data/app/assets/javascripts/crosswalk.js.coffee +17 -19
- data/app/assets/javascripts/custom_calculations.js.coffee +44 -17
- data/app/assets/javascripts/hqmf_util.js.coffee +559 -161
- data/app/assets/javascripts/logging_utils.js.coffee +6 -4
- data/app/assets/javascripts/patient_api_extension.js.coffee +41 -9
- data/app/assets/javascripts/specifics.js.coffee +163 -69
- data/hqmf2js.gemspec +7 -12
- data/lib/assets/javascripts/libraries/map_reduce_utils.js +151 -64
- data/lib/generator/characteristic.js.erb +23 -12
- data/lib/generator/codes_to_json.rb +1 -1
- data/lib/generator/data_criteria.js.erb +15 -3
- data/lib/generator/derived_data.js.erb +5 -0
- data/lib/generator/execution.rb +41 -11
- data/lib/generator/js.rb +74 -41
- data/lib/generator/patient_data.js.erb +1 -1
- data/lib/hqmf2js.rb +0 -1
- data/lib/hquery/engine.rb +3 -1
- data/lib/tasks/convert.rake +20 -12
- data/test/fixtures/NQF59New.json +1423 -0
- data/test/fixtures/fulfills.xml +917 -0
- data/test/fixtures/patients/larry_vanderman.json +573 -654
- data/test/{simplecov.rb → simplecov_init.rb} +0 -0
- data/test/test_helper.rb +2 -3
- data/test/unit/cmd_test.rb +145 -19
- data/test/unit/codes_to_json_test.rb +12 -12
- data/test/unit/custom_calculations_test.rb +2 -6
- data/test/unit/effective_date_test.rb +3 -4
- data/test/unit/erb_context_test.rb +12 -12
- data/test/unit/filter_by_reference_test.rb +39 -0
- data/test/unit/hqmf_from_json_javascript_test.rb +2 -1
- data/test/unit/hqmf_javascript_test.rb +12 -13
- data/test/unit/js_object_test.rb +2 -2
- data/test/unit/library_function_test.rb +210 -42
- data/test/unit/specifics_test.rb +402 -321
- metadata +57 -15
- data/config/warble.rb +0 -144
data/hqmf2js.gemspec
CHANGED
@@ -6,17 +6,12 @@ Gem::Specification.new do |s|
|
|
6
6
|
s.description = "A library for converting HQMF files to executable JavaScript suitable for use with the hQuery Gateway"
|
7
7
|
s.email = "hquery-talk@googlegroups.com"
|
8
8
|
s.homepage = "http://github.com/hquery/hqmf2js"
|
9
|
-
s.authors = ["
|
10
|
-
s.version = '1.
|
11
|
-
|
12
|
-
# s.add_dependency 'nokogiri', '~> 1.5.5'
|
13
|
-
# s.add_dependency 'tilt', '~> 1.3.3'
|
14
|
-
# s.add_dependency 'coffee-script', '~> 2.2.0'
|
15
|
-
# s.add_dependency 'sprockets', '~> 2.2.2'
|
16
|
-
# s.add_development_dependency "awesome_print", "~> 1.1.0"
|
17
|
-
# s.add_dependency 'health-data-standards', '~> 3.1.1'
|
18
|
-
# s.add_dependency 'hquery-patient-api', '~> 1.0.2'
|
19
|
-
|
9
|
+
s.authors = ["The MITRE Corporation"]
|
10
|
+
s.version = '1.4.0'
|
11
|
+
s.license = 'Apache-2.0'
|
20
12
|
s.files = s.files = `git ls-files`.split("\n")
|
21
|
-
end
|
22
13
|
|
14
|
+
s.add_dependency "rails", "~> 4.2"
|
15
|
+
s.add_dependency 'health-data-standards', '~> 4.0'
|
16
|
+
s.add_dependency 'hquery-patient-api', '~> 1.1'
|
17
|
+
end
|
@@ -5,7 +5,12 @@
|
|
5
5
|
|
6
6
|
var root = this;
|
7
7
|
|
8
|
-
|
8
|
+
|
9
|
+
root.emitResult = root.emitResult || function(value) {
|
10
|
+
if (value['IPP'] > 0) emit(ObjectId(), value);
|
11
|
+
}
|
12
|
+
|
13
|
+
root.map = function(record, population, denominator, numerator, exclusion, denexcep, msrpopl, msrpoplex, observ, occurrenceId, isContinuousVariable, stratification, variables, numex) {
|
9
14
|
var value = {IPP: 0, patient_id: record._id,
|
10
15
|
medical_record_id: record.medical_record_number,
|
11
16
|
first: record.first, last: record.last, gender: record.gender,
|
@@ -14,22 +19,22 @@ root.map = function(record, population, denominator, numerator, exclusion, denex
|
|
14
19
|
race: record.race, ethnicity: record.ethnicity, languages: record.languages,
|
15
20
|
payer: extract_payer(record)};
|
16
21
|
|
22
|
+
value.measure_id = hqmfjs.hqmf_id
|
23
|
+
value.sub_id = hqmfjs.sub_id
|
24
|
+
value.nqf_id = hqmfjs.nqf_id
|
25
|
+
value.effective_date = hqmfjs.effective_date;
|
26
|
+
value.test_id = hqmfjs.test_id;
|
27
|
+
|
17
28
|
if (isContinuousVariable) {
|
18
|
-
value = calculateCV(record, population, msrpopl, observ, occurrenceId, value)
|
29
|
+
value = calculateCV(record, population, msrpopl, msrpoplex, observ, occurrenceId, value, stratification, variables)
|
19
30
|
} else {
|
20
|
-
value = calculate(record, population, denominator, numerator, exclusion, denexcep, occurrenceId, value)
|
31
|
+
value = calculate(record, population, denominator, numerator, exclusion, denexcep, occurrenceId, value, stratification, variables, numex)
|
21
32
|
}
|
22
33
|
|
23
34
|
if (typeof Logger != 'undefined') {
|
24
35
|
value['logger'] = Logger.logger
|
25
36
|
value['rationale'] = Logger.rationale
|
26
37
|
}
|
27
|
-
|
28
|
-
value.measure_id = hqmfjs.hqmf_id
|
29
|
-
value.sub_id = hqmfjs.sub_id
|
30
|
-
value.nqf_id = hqmfjs.nqf_id
|
31
|
-
value.effective_date = hqmfjs.effective_date;
|
32
|
-
value.test_id = hqmfjs.test_id;
|
33
38
|
|
34
39
|
if (value.provider_performances) {
|
35
40
|
var tmp = [];
|
@@ -44,8 +49,8 @@ root.map = function(record, population, denominator, numerator, exclusion, denex
|
|
44
49
|
value.provider_performances = null;
|
45
50
|
}
|
46
51
|
|
47
|
-
|
48
|
-
emit(ObjectId(), value);
|
52
|
+
emitResult(value);
|
53
|
+
//emit(ObjectId(), value);
|
49
54
|
};
|
50
55
|
|
51
56
|
root.extract_payer = function(record) {
|
@@ -60,71 +65,153 @@ root.extract_payer = function(record) {
|
|
60
65
|
return payer;
|
61
66
|
};
|
62
67
|
|
63
|
-
root.calculate = function(record, population, denominator, numerator, exclusion, denexcep, occurrenceId, value) {
|
64
|
-
|
68
|
+
root.calculate = function(record, population, denominator, numerator, exclusion, denexcep, occurrenceId, value, stratification, variables, numex) {
|
69
|
+
|
65
70
|
finalSpecifics = {};
|
66
|
-
value = _.extend(value, {DENOM: 0, NUMER: 0, DENEXCEP: 0, DENEX: 0,
|
67
|
-
|
68
|
-
var ipp = population();
|
69
|
-
hqmf.SpecificsManager.storeFinal('IPP', ipp, finalSpecifics);
|
70
|
-
if (hqmf.SpecificsManager.validate(ipp)) {
|
71
|
-
value.IPP = hqmf.SpecificsManager.countUnique(occurrenceId, ipp);
|
72
|
-
var denom = hqmf.SpecificsManager.intersectSpecifics(denominator(), ipp, occurrenceId);
|
73
|
-
hqmf.SpecificsManager.storeFinal('DENOM', denom, finalSpecifics);
|
74
|
-
if (hqmf.SpecificsManager.validate(denom)) {
|
75
|
-
|
76
|
-
value.DENOM = hqmf.SpecificsManager.countUnique(occurrenceId, denom);
|
77
|
-
var exclusions = hqmf.SpecificsManager.intersectSpecifics(exclusion(), denom, occurrenceId);
|
78
|
-
hqmf.SpecificsManager.storeFinal('DENEX', exclusions, finalSpecifics);
|
79
|
-
if (hqmf.SpecificsManager.validate(exclusions)) {
|
80
|
-
value.DENEX = hqmf.SpecificsManager.countUnique(occurrenceId, exclusions);
|
81
|
-
denom = hqmf.SpecificsManager.exclude(occurrenceId, denom, exclusions);
|
82
|
-
}
|
71
|
+
value = _.extend(value, {IPP: 0, DENOM: 0, NUMER: 0, DENEXCEP: 0, DENEX: 0, NUMEX: 0, antinumerator: 0});
|
83
72
|
|
73
|
+
// For the moment, we are doing this to allow for the disabling of storage of finalSpecifics in Mongo.
|
74
|
+
// At some point, it may make more sense to move this to its own variable, rather than using enable_rationale
|
75
|
+
// For example, if Cypress starts running into finalSpecifics size issues.
|
76
|
+
if (Logger.enable_rationale) {
|
77
|
+
value = _.extend(value, {finalSpecifics: finalSpecifics});
|
78
|
+
}
|
79
|
+
|
80
|
+
var strat;
|
81
|
+
var ipp;
|
82
|
+
var validStrat = false;
|
83
|
+
if(stratification) {
|
84
|
+
strat = stratification()
|
85
|
+
hqmf.SpecificsManager.storeFinal('STRAT', strat, finalSpecifics);
|
86
|
+
value.STRAT = hqmf.SpecificsManager.countUnique(occurrenceId, strat);
|
87
|
+
if (hqmf.SpecificsManager.validate(strat)) {
|
88
|
+
ipp = hqmf.SpecificsManager.intersectSpecifics(population(), strat, occurrenceId);
|
89
|
+
validStrat = true;
|
84
90
|
}
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
hqmf.SpecificsManager.
|
93
|
-
if
|
94
|
-
|
91
|
+
} else {
|
92
|
+
ipp = population();
|
93
|
+
}
|
94
|
+
|
95
|
+
if (ipp) {
|
96
|
+
hqmf.SpecificsManager.storeFinal('IPP', ipp, finalSpecifics);
|
97
|
+
if (hqmf.SpecificsManager.validate(ipp)) {
|
98
|
+
value.IPP = hqmf.SpecificsManager.countUnique(occurrenceId, ipp);
|
99
|
+
// if we have a stratification that does not reference an episode of care then we need to take the IPP count
|
100
|
+
if (validStrat && value.STRAT < value.IPP) value.STRAT = value.IPP;
|
101
|
+
var denom = hqmf.SpecificsManager.intersectSpecifics(denominator(), ipp, occurrenceId);
|
102
|
+
hqmf.SpecificsManager.storeFinal('DENOM', denom, finalSpecifics);
|
103
|
+
if (hqmf.SpecificsManager.validate(denom)) {
|
104
|
+
|
105
|
+
value.DENOM = hqmf.SpecificsManager.countUnique(occurrenceId, denom);
|
106
|
+
var exclusions = hqmf.SpecificsManager.intersectSpecifics(exclusion(), denom, occurrenceId);
|
107
|
+
hqmf.SpecificsManager.storeFinal('DENEX', exclusions, finalSpecifics);
|
108
|
+
if (hqmf.SpecificsManager.validate(exclusions)) {
|
109
|
+
value.DENEX = hqmf.SpecificsManager.countUnique(occurrenceId, exclusions);
|
110
|
+
denom = hqmf.SpecificsManager.exclude(occurrenceId, denom, exclusions);
|
111
|
+
}
|
112
|
+
|
95
113
|
}
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
114
|
+
// DENEX is a subset of the denominator, so we should set the specifics before the exclusion
|
115
|
+
// hqmf.SpecificsManager.storeFinal('DENOM', denom, finalSpecifics);
|
116
|
+
|
117
|
+
// we need to check the denominator again to make sure we still have viable candidates after
|
118
|
+
// exclusions have been removed
|
119
|
+
if (hqmf.SpecificsManager.validate(denom)) {
|
120
|
+
var numer = hqmf.SpecificsManager.intersectSpecifics(numerator(), denom, occurrenceId);
|
121
|
+
hqmf.SpecificsManager.storeFinal('NUMER', numer, finalSpecifics);
|
122
|
+
if (hqmf.SpecificsManager.validate(numer)) {
|
123
|
+
value.NUMER = hqmf.SpecificsManager.countUnique(occurrenceId, numer);
|
124
|
+
var numeratorExclusions = hqmf.SpecificsManager.intersectSpecifics(numex(), numer, occurrenceId);
|
125
|
+
hqmf.SpecificsManager.storeFinal('NUMEX', numeratorExclusions, finalSpecifics);
|
126
|
+
if (hqmf.SpecificsManager.validate(numeratorExclusions)) {
|
127
|
+
value.NUMEX = hqmf.SpecificsManager.countUnique(occurrenceId, numeratorExclusions);
|
128
|
+
numer = hqmf.SpecificsManager.exclude(occurrenceId, numer, numeratorExclusions);
|
129
|
+
}
|
130
|
+
}
|
131
|
+
|
132
|
+
var excep = hqmf.SpecificsManager.intersectSpecifics(denexcep(), denom, occurrenceId);
|
133
|
+
hqmf.SpecificsManager.storeFinal('DENEXCEP', excep, finalSpecifics);
|
134
|
+
if (hqmf.SpecificsManager.validate(excep)) {
|
135
|
+
excep = hqmf.SpecificsManager.exclude(occurrenceId, excep, numer);
|
136
|
+
value.DENEXCEP = hqmf.SpecificsManager.countUnique(occurrenceId, excep);
|
137
|
+
denom = hqmf.SpecificsManager.exclude(occurrenceId, denom, excep);
|
138
|
+
}
|
139
|
+
value.antinumerator = value.DENOM-value.NUMER;
|
103
140
|
}
|
104
|
-
|
141
|
+
|
105
142
|
}
|
106
|
-
|
143
|
+
}
|
144
|
+
|
145
|
+
// Adding a separate set of computations for variables. This is because the
|
146
|
+
// logic view displays non-occurrenced variables. However, these are not always
|
147
|
+
// a part of the actual logic computation. This means that they don't get
|
148
|
+
// colored. By adding in a separate set of computations for variables, we
|
149
|
+
// guarantee that they'll be colored.
|
150
|
+
if(variables){
|
151
|
+
variables();
|
107
152
|
}
|
108
153
|
return value;
|
109
154
|
};
|
110
155
|
|
111
|
-
root.calculateCV = function(record, population, msrpopl, observ, occurrenceId, value) {
|
156
|
+
root.calculateCV = function(record, population, msrpopl, msrpoplex, observ, occurrenceId, value, stratification, variables) {
|
112
157
|
finalSpecifics = {};
|
113
|
-
value = _.extend(value, {MSRPOPL: 0,
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
if
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
158
|
+
value = _.extend(value, {MSRPOPL: 0, MSRPOPLEX: 0, values: []});
|
159
|
+
|
160
|
+
// For the moment, we are doing this to allow for the disabling of storage of finalSpecifics in Mongo.
|
161
|
+
// At some point, it may make more sense to move this to its own variable, rather than using enable_rationale
|
162
|
+
// For example, if Cypress starts running into finalSpecifics size issues.
|
163
|
+
if (Logger.enable_rationale) {
|
164
|
+
value = _.extend(value, {finalSpecifics: finalSpecifics});
|
165
|
+
}
|
166
|
+
|
167
|
+
var strat;
|
168
|
+
var ipp;
|
169
|
+
var validStrat = false;
|
170
|
+
if(stratification) {
|
171
|
+
strat = stratification()
|
172
|
+
hqmf.SpecificsManager.storeFinal('STRAT', strat, finalSpecifics);
|
173
|
+
value.STRAT = hqmf.SpecificsManager.countUnique(occurrenceId, strat);
|
174
|
+
if (hqmf.SpecificsManager.validate(strat)) {
|
175
|
+
ipp = hqmf.SpecificsManager.intersectSpecifics(population(), strat, occurrenceId);
|
176
|
+
validStrat = true;
|
177
|
+
}
|
178
|
+
} else {
|
179
|
+
ipp = population();
|
180
|
+
}
|
181
|
+
|
182
|
+
|
183
|
+
if (ipp) {
|
184
|
+
hqmf.SpecificsManager.storeFinal('IPP', ipp, finalSpecifics);
|
185
|
+
if (hqmf.SpecificsManager.validate(ipp)) {
|
186
|
+
value.IPP = hqmf.SpecificsManager.countUnique(occurrenceId, ipp);
|
187
|
+
// if we have a stratification that does not reference an episode of care then we need to take the IPP count
|
188
|
+
if (validStrat && value.STRAT < value.IPP) value.STRAT = value.IPP;
|
189
|
+
var measurePopulation = hqmf.SpecificsManager.intersectSpecifics(msrpopl(), ipp, occurrenceId);
|
190
|
+
hqmf.SpecificsManager.storeFinal('MSRPOPL', measurePopulation, finalSpecifics);
|
191
|
+
if (hqmf.SpecificsManager.validate(measurePopulation)) {
|
192
|
+
value.MSRPOPL = hqmf.SpecificsManager.countUnique(occurrenceId, measurePopulation);
|
193
|
+
|
194
|
+
var measurePopulationExclusions = hqmf.SpecificsManager.intersectSpecifics(msrpoplex(), measurePopulation, occurrenceId);
|
195
|
+
hqmf.SpecificsManager.storeFinal('MSRPOPLEX', measurePopulationExclusions, finalSpecifics);
|
196
|
+
if (hqmf.SpecificsManager.validate(measurePopulationExclusions)) {
|
197
|
+
value.MSRPOPLEX = hqmf.SpecificsManager.countUnique(occurrenceId, measurePopulationExclusions);
|
198
|
+
// Remove from measure population if in measure population exclusion.
|
199
|
+
measurePopulation = hqmf.SpecificsManager.exclude(occurrenceId, measurePopulation, measurePopulationExclusions);
|
200
|
+
}
|
201
|
+
|
202
|
+
var observations = observ(measurePopulation.specificContext);
|
203
|
+
value.values = observations;
|
204
|
+
}
|
125
205
|
}
|
126
206
|
}
|
207
|
+
|
208
|
+
// Adding a separate set of computations for variables. This is because the
|
209
|
+
// logic view displays non-occurrenced variables. However, these are not always
|
210
|
+
// a part of the actual logic computation. This means that they don't get
|
211
|
+
// colored. By adding in a separate set of computations for variables, we
|
212
|
+
// guarantee that they'll be colored.
|
213
|
+
if(variables){
|
214
|
+
variables();
|
215
|
+
}
|
127
216
|
return value;
|
128
217
|
};
|
129
|
-
|
130
|
-
|
@@ -1,30 +1,41 @@
|
|
1
1
|
var value = patient.<%= criteria.property %>(<%= js_for_date_bound(criteria) if criteria.property == :age %>) || null;
|
2
2
|
<%- if criteria.property == :birthtime -%>
|
3
|
-
var events = [value];
|
3
|
+
var events = value ? [value] : [];
|
4
4
|
<%- if criteria.temporal_references -%>
|
5
5
|
<%- criteria.temporal_references.each do |temporal_reference| -%>
|
6
6
|
events = <%= temporal_reference.type %>(events, hqmfjs.<%= temporal_reference.reference.id %>(patient)<%= ", #{js_for_bounds(temporal_reference.range)}" if temporal_reference.range %>);
|
7
7
|
<%- end -%>
|
8
8
|
<%- end -%>
|
9
|
-
|
9
|
+
<%- if criteria.field_values.present? -%>
|
10
|
+
<%- criteria.field_values.keys.each do |field| -%>
|
11
|
+
events = matchingValue(value, <%= js_for_bounds(criteria.field_values[field]) %>).isTrue() ? events : [];
|
12
|
+
<%- end -%>
|
13
|
+
<%- end -%>
|
14
|
+
events.specificContext=events.specificContext||hqmf.SpecificsManager.identity();
|
10
15
|
return events;
|
11
|
-
|
12
|
-
var
|
13
|
-
|
16
|
+
<%- elsif criteria.property == :expired -%>
|
17
|
+
var events = value ? [patient.deathdate()] : [];
|
14
18
|
<%- if criteria.temporal_references -%>
|
15
|
-
|
16
|
-
|
17
|
-
return_value = <%= temporal_reference.type %>(events, hqmfjs.<%= temporal_reference.reference.id %>(patient)<%= ", #{js_for_bounds(temporal_reference.range)}" if temporal_reference.range %>);
|
18
|
-
<%- end -%>
|
19
|
+
<%- criteria.temporal_references.each do |temporal_reference| -%>
|
20
|
+
events = <%= temporal_reference.type %>(events, hqmfjs.<%= temporal_reference.reference.id %>(patient)<%= ", #{js_for_bounds(temporal_reference.range)}" if temporal_reference.range %>);
|
19
21
|
<%- end -%>
|
20
|
-
|
21
|
-
|
22
|
+
<%- end -%>
|
23
|
+
events.specificContext=events.specificContext||hqmf.SpecificsManager.identity();
|
24
|
+
return events;
|
22
25
|
<%- elsif criteria.property == :clinicalTrialParticipant -%>
|
23
26
|
matching = matchingValue(value, 'true');
|
24
27
|
matching.specificContext=hqmf.SpecificsManager.identity();
|
25
28
|
return matching;
|
29
|
+
<%- elsif criteria.property == :race || criteria.property == :payer -%>
|
30
|
+
if (value === null) {
|
31
|
+
matching = new Boolean(false);
|
32
|
+
} else {
|
33
|
+
matching = new Boolean(value.includedIn(<%=criteria.inline_code_list.to_json%>));
|
34
|
+
}
|
35
|
+
matching.specificContext=hqmf.SpecificsManager.identity();
|
36
|
+
return matching;
|
26
37
|
<%- else -%>
|
27
38
|
matching = matchingValue(value, <%= js_for_bounds(criteria.value) %>);
|
28
39
|
matching.specificContext=hqmf.SpecificsManager.identity();
|
29
40
|
return matching;
|
30
|
-
<%- end -%>
|
41
|
+
<%- end -%>
|
@@ -14,7 +14,7 @@ module HQMF2JS
|
|
14
14
|
code_sets = {}
|
15
15
|
value_set.concepts.each do |code_set|
|
16
16
|
code_sets[code_set.code_system_name] ||= []
|
17
|
-
code_sets[code_set.code_system_name]
|
17
|
+
code_sets[code_set.code_system_name] << code_set.code
|
18
18
|
end
|
19
19
|
|
20
20
|
translation[value_set.oid] = code_sets
|
@@ -17,15 +17,27 @@ hqmfjs.<%= js_name(criteria) %> = function(patient, initialSpecificContext) {
|
|
17
17
|
<%- end -%>
|
18
18
|
<%- if criteria.value -%>
|
19
19
|
events = filterEventsByValue(events, <%= js_for_bounds(criteria.value) %>);
|
20
|
+
<%- elsif is_result_criteria(criteria) && !criteria.negation -%>
|
21
|
+
// force a check of results for non-negated result types so that performed does not bleed into results
|
22
|
+
events = filterEventsByValue(events, new ANYNonNull());
|
20
23
|
<%- end -%>
|
21
24
|
<%- if criteria.field_values.present?
|
22
25
|
criteria.field_values.keys.each do |field| -%>
|
23
|
-
events = <%= field_library_method(field) %>(events, "<%= field_method(field) %>", <%= js_for_bounds(criteria.field_values[field]) %>);
|
26
|
+
events = <%= field_library_method(field, criteria.field_values[field]) %>(events, "<%= field_method(field) %>", <%= js_for_bounds(criteria.field_values[field]) %>);
|
24
27
|
<%- end -%>
|
28
|
+
<%- if criteria.subset_operators -%>
|
29
|
+
fields = <%= criteria.field_values.keys.map {|field| field_method(field)} %>;
|
30
|
+
<%- end -%>
|
31
|
+
<%- end -%>
|
32
|
+
<%- if ['transfer_from','transfer_to'].include?(criteria.definition) -%>
|
33
|
+
events = denormalizeEventsByTransfer(events, '<%=criteria.definition.camelize(:lower)%>');
|
34
|
+
<%- end -%>
|
35
|
+
<%- if :communications == criteria.type-%>
|
36
|
+
events = filterEventsByCommunicationDirection(events, '<%=criteria.definition%>');
|
25
37
|
<%- end -%>
|
26
38
|
<%- if criteria.temporal_references and criteria.temporal_references.length > 0 -%>
|
27
39
|
<%- criteria.temporal_references.each do |temporal_reference| -%>
|
28
|
-
if (events.length > 0) events = <%= temporal_reference.type %>(events, hqmfjs.<%= temporal_reference.reference.id %>(patient)<%= ", #{js_for_bounds(temporal_reference.range)}" if temporal_reference.range %>);
|
40
|
+
if (events.length > 0 || !Logger.short_circuit) events = <%= temporal_reference.type %>(events, hqmfjs.<%= temporal_reference.reference.id %>(patient)<%= ", #{js_for_bounds(temporal_reference.range)}" if temporal_reference.range %>);
|
29
41
|
<%- end -%>
|
30
42
|
if (events.length == 0) events.specificContext=hqmf.SpecificsManager.empty();
|
31
43
|
<%- else # no temporal refs -%>
|
@@ -37,7 +49,7 @@ hqmfjs.<%= js_name(criteria) %> = function(patient, initialSpecificContext) {
|
|
37
49
|
<%- end -%>
|
38
50
|
<%- if criteria.subset_operators -%>
|
39
51
|
<%- criteria.subset_operators.select {|subset_operator| subset_operator.type}.each do |subset_operator| -%>
|
40
|
-
events = <%= subset_operator.type %>(events<%= ", #{js_for_bounds(subset_operator.value)}"
|
52
|
+
events = <%= subset_operator.type %>(events<%= if subset_operator.value then ", #{js_for_bounds(subset_operator.value)}"; elsif subset_operator.type == 'DATETIMEDIFF' then ", null"; end %>, initialSpecificContext<%- if ['SUM','MEDIAN'].include?(subset_operator.type) -%>, fields<%- end -%>);
|
41
53
|
<%- end # each operator -%>
|
42
54
|
<%- end # subset operators -%>
|
43
55
|
return events;
|
@@ -3,3 +3,8 @@
|
|
3
3
|
<%= "hqmfjs.#{child}(patient, initialSpecificContext)" %><%= "," if index<criteria.children_criteria.length-1 %>
|
4
4
|
<%- end -%>
|
5
5
|
);
|
6
|
+
<%- if criteria.variable -%>
|
7
|
+
<%- if criteria.specific_occurrence -%>
|
8
|
+
events.specific_occurrence = '<%= criteria.source_data_criteria%>';
|
9
|
+
<%- end -%>
|
10
|
+
<%- end -%>
|
data/lib/generator/execution.rb
CHANGED
@@ -2,7 +2,7 @@ module HQMF2JS
|
|
2
2
|
module Generator
|
3
3
|
class Execution
|
4
4
|
|
5
|
-
|
5
|
+
|
6
6
|
def self.quoted_string_array_or_null(arr)
|
7
7
|
if arr
|
8
8
|
quoted = arr.map {|e| "\"#{e}\""}
|
@@ -20,6 +20,7 @@ module HQMF2JS
|
|
20
20
|
var effective_date = <%= effective_date %>;
|
21
21
|
var enable_logging = <%= enable_logging %>;
|
22
22
|
var enable_rationale = <%= enable_rationale %>;
|
23
|
+
var short_circuit = <%= short_circuit %>;
|
23
24
|
|
24
25
|
<% if (!test_id.nil? && test_id.class==Moped::BSON::ObjectId) %>
|
25
26
|
var test_id = new ObjectId(\"<%= test_id %>\");
|
@@ -32,7 +33,7 @@ module HQMF2JS
|
|
32
33
|
|
33
34
|
hqmfjs.effective_date = effective_date;
|
34
35
|
hqmfjs.test_id = test_id;
|
35
|
-
|
36
|
+
|
36
37
|
#{logic(hqmf_document, population_index, options)}
|
37
38
|
};
|
38
39
|
"
|
@@ -57,19 +58,25 @@ module HQMF2JS
|
|
57
58
|
crosswalk_instrument = "instrumentTrueCrosswalk(hqmfjs);"
|
58
59
|
end
|
59
60
|
|
60
|
-
|
61
|
+
|
61
62
|
"
|
62
63
|
var patient_api = new hQuery.Patient(patient);
|
63
64
|
|
64
65
|
#{gen.to_js(population_index, codes, force_sources)}
|
65
|
-
|
66
|
+
|
66
67
|
var occurrenceId = #{quoted_string_array_or_null(episode_ids)};
|
67
68
|
|
68
69
|
hqmfjs.initializeSpecifics(patient_api, hqmfjs)
|
69
|
-
|
70
|
+
|
70
71
|
var population = function() {
|
71
72
|
return executeIfAvailable(hqmfjs.#{HQMF::PopulationCriteria::IPP}, patient_api);
|
72
73
|
}
|
74
|
+
var stratification = null;
|
75
|
+
if (hqmfjs.#{HQMF::PopulationCriteria::STRAT}) {
|
76
|
+
stratification = function() {
|
77
|
+
return hqmf.SpecificsManager.setIfNull(executeIfAvailable(hqmfjs.#{HQMF::PopulationCriteria::STRAT}, patient_api));
|
78
|
+
}
|
79
|
+
}
|
73
80
|
var denominator = function() {
|
74
81
|
return executeIfAvailable(hqmfjs.#{HQMF::PopulationCriteria::DENOM}, patient_api);
|
75
82
|
}
|
@@ -82,13 +89,25 @@ module HQMF2JS
|
|
82
89
|
var denexcep = function() {
|
83
90
|
return executeIfAvailable(hqmfjs.#{HQMF::PopulationCriteria::DENEXCEP}, patient_api);
|
84
91
|
}
|
92
|
+
var numex = function() {
|
93
|
+
return executeIfAvailable(hqmfjs.#{HQMF::PopulationCriteria::NUMEX}, patient_api);
|
94
|
+
}
|
85
95
|
var msrpopl = function() {
|
86
|
-
|
96
|
+
#{msrpopl_function(custom_functions, population_index)}
|
97
|
+
}
|
98
|
+
var msrpoplex = function() {
|
99
|
+
return executeIfAvailable(hqmfjs.#{HQMF::PopulationCriteria::MSRPOPLEX}, patient_api);
|
87
100
|
}
|
88
101
|
var observ = function(specific_context) {
|
89
102
|
#{observation_function(custom_functions, population_index)}
|
90
103
|
}
|
91
|
-
|
104
|
+
|
105
|
+
var variables = function() {
|
106
|
+
if (Logger.enable_rationale) {
|
107
|
+
return executeIfAvailable(hqmfjs.VARIABLES, patient_api);
|
108
|
+
}
|
109
|
+
}
|
110
|
+
|
92
111
|
var executeIfAvailable = function(optionalFunction, patient_api) {
|
93
112
|
if (typeof(optionalFunction)==='function') {
|
94
113
|
result = optionalFunction(patient_api);
|
@@ -105,15 +124,18 @@ module HQMF2JS
|
|
105
124
|
Logger.logger = [];
|
106
125
|
Logger.rationale={};
|
107
126
|
if (typeof short_circuit == 'undefined') short_circuit = true;
|
108
|
-
|
127
|
+
|
109
128
|
// turn on logging if it is enabled
|
110
129
|
if (enable_logging || enable_rationale) {
|
111
130
|
injectLogger(hqmfjs, enable_logging, enable_rationale, short_circuit);
|
112
|
-
}
|
131
|
+
} else {
|
132
|
+
Logger.enable_rationale = false;
|
133
|
+
Logger.short_circuit = short_circuit;
|
134
|
+
}
|
113
135
|
}
|
114
136
|
|
115
137
|
try {
|
116
|
-
map(patient, population, denominator, numerator, exclusion, denexcep, msrpopl, observ, occurrenceId,#{continuous_variable});
|
138
|
+
map(patient, population, denominator, numerator, exclusion, denexcep, msrpopl, msrpoplex, observ, occurrenceId,#{continuous_variable},stratification, variables, numex);
|
117
139
|
} catch(err) {
|
118
140
|
print(err.stack);
|
119
141
|
throw err;
|
@@ -139,6 +161,14 @@ module HQMF2JS
|
|
139
161
|
|
140
162
|
end
|
141
163
|
|
164
|
+
def self.msrpopl_function(custom_functions, population_index)
|
165
|
+
if (custom_functions && custom_functions[HQMF::PopulationCriteria::MSRPOPL])
|
166
|
+
"return #{custom_functions[HQMF::PopulationCriteria::MSRPOPL]}(patient_api, hqmfjs)"
|
167
|
+
else
|
168
|
+
"return executeIfAvailable(hqmfjs.#{HQMF::PopulationCriteria::MSRPOPL}, patient_api);"
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
142
172
|
end
|
143
173
|
end
|
144
|
-
end
|
174
|
+
end
|