hqmf2js 1.3.0 → 1.4.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.
- 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
|