hqmf2js 1.3.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +5 -13
  2. data/.travis.yml +1 -1
  3. data/Gemfile +1 -25
  4. data/Gemfile.lock +170 -146
  5. data/app/assets/javascripts/crosswalk.js.coffee +17 -19
  6. data/app/assets/javascripts/custom_calculations.js.coffee +44 -17
  7. data/app/assets/javascripts/hqmf_util.js.coffee +559 -161
  8. data/app/assets/javascripts/logging_utils.js.coffee +6 -4
  9. data/app/assets/javascripts/patient_api_extension.js.coffee +41 -9
  10. data/app/assets/javascripts/specifics.js.coffee +163 -69
  11. data/hqmf2js.gemspec +7 -12
  12. data/lib/assets/javascripts/libraries/map_reduce_utils.js +151 -64
  13. data/lib/generator/characteristic.js.erb +23 -12
  14. data/lib/generator/codes_to_json.rb +1 -1
  15. data/lib/generator/data_criteria.js.erb +15 -3
  16. data/lib/generator/derived_data.js.erb +5 -0
  17. data/lib/generator/execution.rb +41 -11
  18. data/lib/generator/js.rb +74 -41
  19. data/lib/generator/patient_data.js.erb +1 -1
  20. data/lib/hqmf2js.rb +0 -1
  21. data/lib/hquery/engine.rb +3 -1
  22. data/lib/tasks/convert.rake +20 -12
  23. data/test/fixtures/NQF59New.json +1423 -0
  24. data/test/fixtures/fulfills.xml +917 -0
  25. data/test/fixtures/patients/larry_vanderman.json +573 -654
  26. data/test/{simplecov.rb → simplecov_init.rb} +0 -0
  27. data/test/test_helper.rb +2 -3
  28. data/test/unit/cmd_test.rb +145 -19
  29. data/test/unit/codes_to_json_test.rb +12 -12
  30. data/test/unit/custom_calculations_test.rb +2 -6
  31. data/test/unit/effective_date_test.rb +3 -4
  32. data/test/unit/erb_context_test.rb +12 -12
  33. data/test/unit/filter_by_reference_test.rb +39 -0
  34. data/test/unit/hqmf_from_json_javascript_test.rb +2 -1
  35. data/test/unit/hqmf_javascript_test.rb +12 -13
  36. data/test/unit/js_object_test.rb +2 -2
  37. data/test/unit/library_function_test.rb +210 -42
  38. data/test/unit/specifics_test.rb +402 -321
  39. metadata +57 -15
  40. data/config/warble.rb +0 -144
@@ -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 = ["Marc Hadley", "Andre Quina", "Andy Gregorowicz"]
10
- s.version = '1.3.0'
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
- root.map = function(record, population, denominator, numerator, exclusion, denexcep, msrpopl, observ, occurrenceId, isContinuousVariable) {
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
- //if (value['IPP'] > 0) emit(ObjectId(), value);
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, antinumerator: 0, finalSpecifics: finalSpecifics});
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
- // DENEX is a subset of the denominator, so we should set the specifics before the exclusion
86
- // hqmf.SpecificsManager.storeFinal('DENOM', denom, finalSpecifics);
87
-
88
- // we need to check the denominator again to make sure we still have viable candidates after
89
- // exclusions have been removed
90
- if (hqmf.SpecificsManager.validate(denom)) {
91
- var numer = hqmf.SpecificsManager.intersectSpecifics(numerator(), denom, occurrenceId);
92
- hqmf.SpecificsManager.storeFinal('NUMER', numer, finalSpecifics);
93
- if (hqmf.SpecificsManager.validate(numer)) {
94
- value.NUMER = hqmf.SpecificsManager.countUnique(occurrenceId, numer);
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
- var excep = hqmf.SpecificsManager.intersectSpecifics(denexcep(), denom, occurrenceId);
98
- hqmf.SpecificsManager.storeFinal('DENEXCEP', excep, finalSpecifics);
99
- if (hqmf.SpecificsManager.validate(excep)) {
100
- excep = hqmf.SpecificsManager.exclude(occurrenceId, excep, numer);
101
- value.DENEXCEP = hqmf.SpecificsManager.countUnique(occurrenceId, excep);
102
- denom = hqmf.SpecificsManager.exclude(occurrenceId, denom, excep);
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
- value.antinumerator = value.DENOM-value.NUMER;
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, values: [], finalSpecifics: finalSpecifics});
114
-
115
- var ipp = population()
116
- hqmf.SpecificsManager.storeFinal('IPP', ipp, finalSpecifics);
117
- if (hqmf.SpecificsManager.validate(ipp)) {
118
- value.IPP = hqmf.SpecificsManager.countUnique(occurrenceId, ipp);
119
- var measurePopulation = hqmf.SpecificsManager.intersectSpecifics(msrpopl(), ipp, occurrenceId);
120
- hqmf.SpecificsManager.storeFinal('MSRPOPL', measurePopulation, finalSpecifics);
121
- if (hqmf.SpecificsManager.validate(measurePopulation)) {
122
- var observations = observ(measurePopulation.specificContext);
123
- value.MSRPOPL = hqmf.SpecificsManager.countUnique(occurrenceId, measurePopulation);
124
- value.values = observations;
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
- events.specificContext=hqmf.SpecificsManager.identity();
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
- <%- elsif criteria.property == :expired %>
12
- var return_value = matchingValue(value, 'true');
13
-
16
+ <%- elsif criteria.property == :expired -%>
17
+ var events = value ? [patient.deathdate()] : [];
14
18
  <%- if criteria.temporal_references -%>
15
- var events = [patient.deathdate()];
16
- <%- criteria.temporal_references.each do |temporal_reference| -%>
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
- return_value.specificContext=hqmf.SpecificsManager.identity();
21
- return return_value
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].concat(code_set.code.to_a)
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)}" if subset_operator.value %>, initialSpecificContext);
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 -%>
@@ -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
- return executeIfAvailable(hqmfjs.#{HQMF::PopulationCriteria::MSRPOPL}, patient_api);
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