hqmf2js 1.2.1 → 1.3.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.
Files changed (39) hide show
  1. checksums.yaml +15 -0
  2. data/.travis.yml +2 -5
  3. data/Gemfile +6 -4
  4. data/Gemfile.lock +83 -86
  5. data/Rakefile +9 -5
  6. data/app/assets/javascripts/hqmf_util.js.coffee +98 -23
  7. data/app/assets/javascripts/logging_utils.js.coffee +25 -16
  8. data/app/assets/javascripts/patient_api_extension.js.coffee +85 -0
  9. data/app/assets/javascripts/specifics.js.coffee +60 -14
  10. data/hqmf2js.gemspec +8 -8
  11. data/lib/assets/javascripts/libraries/map_reduce_utils.js +130 -0
  12. data/lib/generator/characteristic.js.erb +28 -17
  13. data/lib/generator/codes_to_json.rb +5 -5
  14. data/lib/generator/data_criteria.js.erb +5 -5
  15. data/lib/generator/execution.rb +144 -0
  16. data/lib/generator/js.rb +46 -21
  17. data/lib/generator/observation_criteria.js.erb +1 -1
  18. data/lib/generator/patient_data.js.erb +22 -19
  19. data/lib/generator/population_criteria.js.erb +6 -1
  20. data/lib/generator/precondition.js.erb +5 -7
  21. data/lib/hqmf2js.rb +1 -0
  22. data/test/fixtures/codes/codes.json +54 -0
  23. data/test/fixtures/json/0495.json +1014 -0
  24. data/test/fixtures/json/59New.json +148 -0
  25. data/test/fixtures/json/data_criteria/specific_occurrence.json +27 -0
  26. data/test/fixtures/json/data_criteria/temporals_with_anynonnull.json +27 -0
  27. data/test/fixtures/patients/larry_vanderman.json +4 -4
  28. data/test/simplecov.rb +19 -0
  29. data/test/test_helper.rb +1 -1
  30. data/test/unit/cmd_test.rb +92 -0
  31. data/test/unit/codes_to_json_test.rb +32 -0
  32. data/test/unit/erb_context_test.rb +64 -0
  33. data/test/unit/hqmf_from_json_javascript_test.rb +37 -2
  34. data/test/unit/hqmf_javascript_test.rb +18 -0
  35. data/test/unit/js_object_test.rb +27 -0
  36. data/test/unit/library_function_test.rb +22 -21
  37. data/test/unit/specifics_test.rb +7 -2
  38. metadata +16 -121
  39. data/lib/tasks/cover_me.rake +0 -8
data/lib/generator/js.rb CHANGED
@@ -166,8 +166,12 @@ module HQMF2JS
166
166
  def initialize(doc)
167
167
  @doc = doc
168
168
  end
169
+
170
+ def self.map_reduce_utils
171
+ File.read(File.expand_path(File.join('..', '..', "assets",'javascripts','libraries','map_reduce_utils.js'), __FILE__))
172
+ end
169
173
 
170
- def to_js(population_index=0, codes=nil)
174
+ def to_js(population_index=0, codes=nil, force_sources=nil)
171
175
  population_index ||= 0
172
176
  population = @doc.populations[population_index]
173
177
 
@@ -177,14 +181,23 @@ module HQMF2JS
177
181
  oid_dictionary = "<%= oid_dictionary %>"
178
182
  end
179
183
 
184
+ sub_ids = ('a'..'zz').to_a
185
+ sub_id = @doc.populations.size > 1 ? "'#{sub_ids[population_index]}'" : "null";
186
+
187
+
180
188
  "
181
189
  // #########################
182
190
  // ##### DATA ELEMENTS #####
183
191
  // #########################
184
192
 
193
+ hqmfjs.nqf_id = '#{@doc.id}';
194
+ hqmfjs.hqmf_id = '#{@doc.hqmf_id}';
195
+ hqmfjs.sub_id = #{sub_id};
196
+ if (typeof(test_id) == 'undefined') hqmfjs.test_id = null;
197
+
185
198
  OidDictionary = #{oid_dictionary};
186
199
 
187
- #{js_for_data_criteria()}
200
+ #{js_for_data_criteria(force_sources)}
188
201
 
189
202
  // #########################
190
203
  // ##### MEASURE LOGIC #####
@@ -193,7 +206,7 @@ module HQMF2JS
193
206
  #{js_initialize_specifics(@doc.source_data_criteria)}
194
207
 
195
208
  // INITIAL PATIENT POPULATION
196
- #{js_for(population[HQMF::PopulationCriteria::IPP], HQMF::PopulationCriteria::IPP, true)}
209
+ #{js_for(population[HQMF::PopulationCriteria::IPP], HQMF::PopulationCriteria::IPP)}
197
210
  // DENOMINATOR
198
211
  #{js_for(population[HQMF::PopulationCriteria::DENOM], HQMF::PopulationCriteria::DENOM, true)}
199
212
  // NUMERATOR
@@ -236,29 +249,34 @@ module HQMF2JS
236
249
  end
237
250
 
238
251
  # Generate JS for a HQMF2::DataCriteria
239
- def js_for_data_criteria
240
- HQMF2JS::Generator.render_template('data_criteria', {'all_criteria' => @doc.specific_occurrence_source_data_criteria.concat(@doc.all_data_criteria), 'measure_period' => @doc.measure_period})
252
+ def js_for_data_criteria(force_sources=nil)
253
+ HQMF2JS::Generator.render_template('data_criteria', {'all_criteria' => @doc.specific_occurrence_source_data_criteria(force_sources).concat(@doc.all_data_criteria), 'measure_period' => @doc.measure_period})
241
254
  end
242
255
 
243
- def self.library_functions(check_crosswalk=false)
256
+ def self.library_functions(check_crosswalk=false, include_underscore=true)
244
257
  ctx = Sprockets::Environment.new(File.expand_path("../../..", __FILE__))
245
258
  Tilt::CoffeeScriptTemplate.default_bare = true
246
259
  ctx.append_path "app/assets/javascripts"
247
260
 
248
- libraries = ["// #########################\n// ###### Underscore.js #######\n// #######################\n",
249
- ctx.find_asset('underscore').to_s,
250
- "// #########################\n// ###### PATIENT API #######\n// #########################\n",
251
- HqueryPatientApi::Generator.patient_api_javascript.to_s,
252
- "// #########################\n// ## SPECIFIC OCCURRENCES ##\n// #########################\n",
253
- ctx.find_asset('specifics').to_s,
254
- "// #########################\n// ### LIBRARY FUNCTIONS ####\n// #########################\n",
255
- ctx.find_asset('hqmf_util').to_s,
256
- "// #########################\n// ### PATIENT EXTENSION ####\n// #########################\n",
257
- ctx.find_asset('patient_api_extension').to_s,
258
- "// #########################\n// ## CUSTOM CALCULATIONS ###\n// #########################\n",
259
- ctx.find_asset('custom_calculations').to_s,
260
- "// #########################\n// ##### LOGGING UTILS ######\n// #########################\n",
261
- ctx.find_asset('logging_utils').to_s]
261
+ libraries = []
262
+
263
+ if include_underscore
264
+ libraries += ["// #########################\n// ###### Underscore.js #######\n// #######################\n",
265
+ ctx.find_asset('underscore').to_s]
266
+ end
267
+
268
+ libraries += ["// #########################\n// ###### PATIENT API #######\n// #########################\n",
269
+ HqueryPatientApi::Generator.patient_api_javascript.to_s,
270
+ "// #########################\n// ## SPECIFIC OCCURRENCES ##\n// #########################\n",
271
+ ctx.find_asset('specifics').to_s,
272
+ "// #########################\n// ### LIBRARY FUNCTIONS ####\n// #########################\n",
273
+ ctx.find_asset('hqmf_util').to_s,
274
+ "// #########################\n// ### PATIENT EXTENSION ####\n// #########################\n",
275
+ ctx.find_asset('patient_api_extension').to_s,
276
+ "// #########################\n// ## CUSTOM CALCULATIONS ###\n// #########################\n",
277
+ ctx.find_asset('custom_calculations').to_s,
278
+ "// #########################\n// ##### LOGGING UTILS ######\n// #########################\n",
279
+ ctx.find_asset('logging_utils').to_s]
262
280
 
263
281
  # check for code set crosswalks
264
282
  if (check_crosswalk)
@@ -270,6 +288,13 @@ module HQMF2JS
270
288
 
271
289
  end
272
290
 
291
+ # Allow crosswalk functionality to be loaded separately from main JS libraries
292
+ def self.crosswalk_functions
293
+ ctx = Sprockets::Environment.new(File.expand_path("../../..", __FILE__))
294
+ Tilt::CoffeeScriptTemplate.default_bare = true
295
+ ctx.append_path "app/assets/javascripts"
296
+ ctx.find_asset('crosswalk').to_s
297
+ end
273
298
  end
274
299
 
275
300
  # Simple class to issue monotonically increasing integer identifiers
@@ -293,4 +318,4 @@ module HQMF2JS
293
318
  include Singleton
294
319
  end
295
320
  end
296
- end
321
+ end
@@ -1,4 +1,4 @@
1
1
  hqmfjs.<%= type %> = function(patient, initialSpecificContext) {
2
- return <%= js_for_precondition(criteria.preconditions()[0], 0, true) -%>;
2
+ return <%= js_for_precondition(criteria.preconditions()[0], 0, true) -%>(patient, initialSpecificContext);
3
3
  };
4
4
 
@@ -1,22 +1,25 @@
1
- var events = patient.<%= patient_api_method(criteria) %>();
2
- <%- if criteria.specific_occurrence -%>
3
- events.specific_occurrence = '<%= criteria.source_data_criteria %>'
4
- <%- end -%>
5
- <%- if criteria.status -%>
6
- events = events.withStatuses(["<%= criteria.status %>"]<%= ", false" if criteria.hard_status %>);
7
- <%- end -%>
8
- <%- if criteria.negation -%>
9
- events = events.withNegation(<%= "getCodes(\"#{criteria.negation_code_list_id}\")" if criteria.negation_code_list_id %>);
10
- <%- else -%>
11
- events = events.withoutNegation();
12
- <%- end -%>
13
- var codes = <%= js_for_code_list(criteria) %>;
14
- var start = null;
15
- var end = null;
1
+ <%- eventType = patient_api_method(criteria) -%>
2
+ <%- valueSetId = criteria.code_list_id -%>
3
+ <%- valueSet = criteria.inline_code_list ? js_for_code_list(criteria) : nil -%>
4
+ <%- negationValueSetId = criteria.negation_code_list_id -%>
5
+ <%- statuses = criteria.status ? "[\"#{criteria.status}\"]" : nil -%>
6
+ <%- includeEventsWithoutStatus = criteria.hard_status ? false : true -%>
7
+ <%- start = nil -%>
8
+ <%- stop = nil -%>
16
9
  <%- if criteria.effective_time -%>
17
10
  <%- startExp = js_for_value(criteria.effective_time.low) -%>
18
- start = <%= startExp %><%= '.asDate()' if startExp != 'null' %>;
19
- <%- endExp = js_for_value(criteria.effective_time.high) -%>
20
- end = <%= endExp %><%= '.asDate()' if endExp != 'null' %>;
11
+ <%- start = startExp+'.asDate()' if startExp != 'null' -%>
12
+ <%- stopExp = js_for_value(criteria.effective_time.high) -%>
13
+ <%- stop = stopExp+'.asDate()' if stopExp != 'null' -%>
21
14
  <%- end -%>
22
- events = events.match(codes, start, end, true);
15
+ var eventCriteria = {"type": "<%= eventType %>"<%- -%>
16
+ <%= ", \"statuses\": #{statuses}" if statuses %> <%- -%>
17
+ <%= ", \"includeEventsWithoutStatus\": #{includeEventsWithoutStatus}" if includeEventsWithoutStatus %> <%- -%>
18
+ <%= ", \"negated\": #{criteria.negation}" if criteria.negation %> <%- -%>
19
+ <%= ", \"negationValueSetId\": \"#{negationValueSetId}\"" if criteria.negation && negationValueSetId %> <%- -%>
20
+ <%= ", \"valueSetId\": \"#{valueSetId}\"" if valueSetId %> <%- -%>
21
+ <%= ", \"valueSet\": #{valueSet}" if valueSet %> <%- -%>
22
+ <%= ", \"start\": #{start}" if start %> <%- -%>
23
+ <%= ", \"stop\": #{stop}" if stop %> <%- -%>
24
+ <%= ", \"specificOccurrence\": \"#{criteria.source_data_criteria}\"" if criteria.specific_occurrence %>};
25
+ var events = patient.getEvents(eventCriteria);
@@ -1,4 +1,9 @@
1
1
  hqmfjs.<%= type %> = function(patient, initialSpecificContext) {
2
- return <%= js_for_precondition(criteria, 0, true) -%>;
2
+ population_criteria_fn = <%= js_for_precondition(criteria, 0, true) -%>;
3
+ if (typeof(population_criteria_fn) == 'function') {
4
+ return population_criteria_fn();
5
+ } else {
6
+ return population_criteria_fn;
7
+ }
3
8
  };
4
9
 
@@ -1,16 +1,14 @@
1
1
  <%- if precondition.conjunction? -%>
2
2
  <%- if indent>0 -%>
3
- <%= "\n#{' '*(indent+1)}#{conjunction_code_for(precondition)}('#{precondition.id}'," -%>
3
+ <%= "\n#{' '*(indent+1)}#{conjunction_code_for(precondition)}('#{precondition.id}', patient, initialSpecificContext," -%>
4
4
  <%- else -%>
5
- <%= "#{conjunction_code_for(precondition)}('#{precondition.id}'," -%>
5
+ <%= "#{conjunction_code_for(precondition)}('#{precondition.id}', patient, initialSpecificContext," -%>
6
6
  <%- end -%>
7
7
  <%- precondition.preconditions.each_with_index do |child, index| -%>
8
- <%= "#{' '*(indent+1)}#{js_for_precondition(child, indent+1, context)}" -%>
8
+ <%= "#{js_for_precondition(child, indent+1, context)}" -%>
9
9
  <%= "," if index < precondition.preconditions.length-1 -%>
10
10
  <%- end -%>
11
11
  <%= "\n#{' '*(indent+1)})" -%>
12
- <%- elsif context -%>
13
- <%= " hqmfjs.#{js_name(precondition.reference)}(patient, initialSpecificContext)" -%>
14
- <%- else -%>
15
- <%= "\n#{' '*(indent+1)}hqmfjs.#{js_name(precondition.reference)}(patient)" -%>
12
+ <%- else # !precondition.conjunction? -%>
13
+ <%= " hqmfjs.#{js_name(precondition.reference)}" -%>
16
14
  <%- end -%>
data/lib/hqmf2js.rb CHANGED
@@ -16,5 +16,6 @@ require 'hqmf-parser'
16
16
  require_relative 'generator/js'
17
17
  require_relative 'generator/codes_to_json'
18
18
  require_relative 'generator/converter'
19
+ require_relative 'generator/execution'
19
20
 
20
21
  Tilt::CoffeeScriptTemplate.default_bare = true
@@ -0,0 +1,54 @@
1
+ [{
2
+ "concepts": [
3
+ {
4
+ "code": "123A",
5
+ "code_system_name": "SNOMED-CT"
6
+ },
7
+ {
8
+ "code": "124B",
9
+ "code_system_name": "SNOMED-CT"
10
+ },
11
+ {
12
+ "code": "125C",
13
+ "code_system_name": "CPT"
14
+ },
15
+ {
16
+ "code": "126D",
17
+ "code_system_name": "CPT"
18
+ },
19
+ {
20
+ "code": "127E",
21
+ "code_system_name": "CPT"
22
+ }
23
+ ],
24
+ "display_name": "ABD-XYZ",
25
+ "oid": "1.2.3.4.6",
26
+ "version": "20130614"
27
+ },
28
+ {
29
+ "concepts": [
30
+ {
31
+ "code": "123",
32
+ "code_system_name": "SNOMED-CT"
33
+ },
34
+ {
35
+ "code": "124",
36
+ "code_system_name": "SNOMED-CT"
37
+ },
38
+ {
39
+ "code": "125",
40
+ "code_system_name": "SNOMED-CT"
41
+ },
42
+ {
43
+ "code": "126",
44
+ "code_system_name": "ICD-9-CM"
45
+ },
46
+ {
47
+ "code": "127",
48
+ "code_system_name": "ICD-9-CM"
49
+ }
50
+ ],
51
+ "display_name": "ABC-XYZ",
52
+ "oid": "1.2.3.4.5",
53
+ "version": "20130614"
54
+ }]