hqmf2js 1.2.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }]