hqmf2js 1.2.0 → 1.2.1

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.
data/.travis.yml CHANGED
@@ -1,7 +1,7 @@
1
1
  language: ruby
2
2
 
3
3
  rvm:
4
- - 1.9.2
4
+ - 1.9.3
5
5
 
6
6
  script: bundle exec rake
7
7
 
data/Gemfile.lock CHANGED
@@ -1,10 +1,10 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- hqmf2js (1.2.0)
4
+ hqmf2js (1.2.1)
5
5
  coffee-script (~> 2.2.0)
6
- health-data-standards (~> 3.0.1)
7
- hquery-patient-api (~> 1.0.1)
6
+ health-data-standards (~> 3.1.1)
7
+ hquery-patient-api (~> 1.0.2)
8
8
  nokogiri (~> 1.5.5)
9
9
  sprockets (~> 2.2.2)
10
10
  tilt (~> 1.3.3)
@@ -43,7 +43,6 @@ GEM
43
43
  arel (3.0.2)
44
44
  awesome_print (1.1.0)
45
45
  builder (3.0.4)
46
- choice (0.1.6)
47
46
  coderay (1.0.8)
48
47
  coffee-rails (3.2.2)
49
48
  coffee-script (>= 2.2.0)
@@ -60,34 +59,23 @@ GEM
60
59
  erubis (2.7.0)
61
60
  execjs (1.4.0)
62
61
  multi_json (~> 1.0)
63
- faraday (0.8.6)
64
- multipart-post (~> 1.1)
65
- google-spreadsheet-ruby (0.1.8)
66
- nokogiri (>= 1.4.3.1)
67
- oauth (>= 0.3.6)
68
- oauth2 (>= 0.5.0)
69
62
  hashie (1.2.0)
70
- health-data-standards (3.0.1)
63
+ health-data-standards (3.1.1)
71
64
  activesupport (~> 3.2.9)
72
65
  builder (~> 3.0.0)
73
66
  erubis (~> 2.7.0)
74
- google-spreadsheet-ruby (= 0.1.8)
75
67
  log4r (~> 1.1.10)
68
+ memoist (~> 0.9.0)
76
69
  mongoid (~> 3.1.0)
77
70
  nokogiri (~> 1.5.5)
78
71
  rest-client (~> 1.6.7)
79
- roo (= 1.10.1)
80
72
  rubyzip
81
- spreadsheet (= 0.6.8)
82
73
  uuid (~> 2.3.5)
83
74
  hike (1.2.1)
84
- hquery-patient-api (1.0.1)
85
- httpauth (0.2.0)
75
+ hquery-patient-api (1.0.2)
86
76
  i18n (0.6.1)
87
77
  journey (1.0.4)
88
78
  json (1.7.5)
89
- jwt (0.1.5)
90
- multi_json (>= 1.0)
91
79
  libv8 (3.3.10.4)
92
80
  log4r (1.1.10)
93
81
  macaddr (1.6.1)
@@ -96,27 +84,18 @@ GEM
96
84
  i18n (>= 0.4.0)
97
85
  mime-types (~> 1.16)
98
86
  treetop (~> 1.4.8)
87
+ memoist (0.9.0)
99
88
  method_source (0.8.1)
100
89
  mime-types (1.20.1)
101
90
  minitest (4.3.2)
102
- mongoid (3.1.2)
91
+ mongoid (3.1.3)
103
92
  activemodel (~> 3.2)
104
93
  moped (~> 1.4.2)
105
94
  origin (~> 1.0)
106
95
  tzinfo (~> 0.3.22)
107
- moped (1.4.2)
96
+ moped (1.4.5)
108
97
  multi_json (1.5.0)
109
- multi_xml (0.5.3)
110
- multipart-post (1.2.0)
111
98
  nokogiri (1.5.6)
112
- oauth (0.4.7)
113
- oauth2 (0.9.1)
114
- faraday (~> 0.8)
115
- httpauth (~> 0.1)
116
- jwt (~> 0.1.4)
117
- multi_json (~> 1.0)
118
- multi_xml (~> 0.5)
119
- rack (~> 1.2)
120
99
  origin (1.0.11)
121
100
  polyglot (0.3.3)
122
101
  pry (0.9.10)
@@ -150,14 +129,6 @@ GEM
150
129
  json (~> 1.4)
151
130
  rest-client (1.6.7)
152
131
  mime-types (>= 1.16)
153
- roo (1.10.1)
154
- choice (>= 0.1.4)
155
- google-spreadsheet-ruby (>= 0.1.5)
156
- nokogiri (>= 1.5.0)
157
- rubyzip (>= 0.9.4)
158
- spreadsheet (> 0.6.4)
159
- todonotes (>= 0.1.0)
160
- ruby-ole (1.2.11.6)
161
132
  rubyzip (0.9.9)
162
133
  sass (3.2.3)
163
134
  sass-rails (3.2.5)
@@ -165,8 +136,6 @@ GEM
165
136
  sass (>= 3.1.10)
166
137
  tilt (~> 1.3)
167
138
  slop (3.3.3)
168
- spreadsheet (0.6.8)
169
- ruby-ole (>= 1.0)
170
139
  sprockets (2.2.2)
171
140
  hike (~> 1.2)
172
141
  multi_json (~> 1.0)
@@ -177,8 +146,6 @@ GEM
177
146
  libv8 (~> 3.3.10)
178
147
  thor (0.16.0)
179
148
  tilt (1.3.3)
180
- todonotes (0.1.1)
181
- log4r
182
149
  treetop (1.4.12)
183
150
  polyglot
184
151
  polyglot (>= 0.3.1)
@@ -0,0 +1,72 @@
1
+ class @CrosswalkManager
2
+ @matchedSystems: {}
3
+ @trueMatchedSystems: {}
4
+ @tmpTrueMatchedSystems: {}
5
+ @clearValidateCodeSystemData: () ->
6
+ CrosswalkManager.matchedSystems = {}
7
+ CrosswalkManager.trueMatchedSystems = {}
8
+ CrosswalkManager.tmpTrueMatchedSystems = {}
9
+
10
+ hQuery.Patient::validateCodeSystems = () ->
11
+ sections = ['encounters','medications','conditions','procedures','results','vitalSigns','immunizations','allergies','pregnancies','socialHistories','careGoals','medicalEquipment','functionalStatuses']
12
+ fullMatch = true
13
+ for section in sections
14
+ for entry in this[section]()
15
+ matchedSystems = CrosswalkManager.matchedSystems[entry.id]
16
+ if (matchedSystems? && _.keys(matchedSystems).length > 0)
17
+ matches = _.keys(entry.json.codes).length == _.keys(matchedSystems).length
18
+ fullMatch = fullMatch && matches
19
+ Logger.info("#{entry.json['description']} -> #{_.keys(entry.json.codes)} != #{_.keys(matchedSystems)}") if !matches
20
+ # trueMatchedSystems = CrosswalkManager.trueMatchedSystems[entry.id]
21
+ # if (trueMatchedSystems? && _.keys(trueMatchedSystems).length > 0)
22
+ # matches = _.keys(entry.json.codes).length == _.keys(trueMatchedSystems).length
23
+ # fullMatch = fullMatch && matches
24
+ # Logger.info("TRUE MATCH: #{entry.json['description']} -> #{_.keys(entry.json.codes)} != #{_.keys(trueMatchedSystems)}") if !matches
25
+ CrosswalkManager.clearValidateCodeSystemData()
26
+ fullMatch
27
+
28
+ hQuery.CodedEntry::includesCodeFrom = (codeSet) ->
29
+ allTrue = true
30
+ oneTrue = false
31
+ # tmpTrueMatchedSystems = {}
32
+ matchedSystems = CrosswalkManager.matchedSystems[@id]
33
+ for codedValue in @_type
34
+ thisResult = codedValue.includedIn(codeSet)
35
+ oneTrue = oneTrue || thisResult
36
+ allTrue = allTrue && thisResult
37
+ matchedSystems = {} unless matchedSystems?
38
+ matchedSystems[codedValue.codeSystemName()] = true if (thisResult)
39
+ # tmpTrueMatchedSystems[codedValue.codeSystemName()] = true if (thisResult)
40
+ if (oneTrue && !allTrue)
41
+ Logger.info("*** #{@json['description']}")
42
+ for codedValue in @_type
43
+ thisResult = codedValue.includedIn(codeSet)
44
+ Logger.info("*** Logger is #{thisResult} for: #{Logger.toJson(codedValue)}")
45
+ CrosswalkManager.matchedSystems[@id] = matchedSystems
46
+ # CrosswalkManager.tmpTrueMatchedSystems[@id] = tmpTrueMatchedSystems
47
+ oneTrue
48
+
49
+ instrumentTrueCrosswalk = (hqmfjs) ->
50
+ # CrosswalkManager.clearValidateCodeSystemData()
51
+ # _.each(_.functions(hqmfjs), (method) ->
52
+ # hqmfjs[method] = _.wrap(hqmfjs[method], (func) ->
53
+
54
+ # args = Array.prototype.slice.call(arguments,1)
55
+
56
+ # results = func.apply(this, args)
57
+ # tmp_results = results
58
+ # tmp_results = [results] unless _.isArray(tmp_results)
59
+
60
+ # _.each(tmp_results, (result) ->
61
+ # if result.json? && CrosswalkManager.tmpTrueMatchedSystems[result.id]?
62
+ # tmpTrueMatchedSystems = CrosswalkManager.tmpTrueMatchedSystems[result.id]
63
+ # CrosswalkManager.trueMatchedSystems[result.id] = {} unless CrosswalkManager.trueMatchedSystems[result.id]
64
+ # Logger.info("TRUE_MATCHED: #{result.json['description']} - #{_.keys(tmpTrueMatchedSystems)}!!!")
65
+ # _.each(_.keys(tmpTrueMatchedSystems), (key) ->
66
+ # CrosswalkManager.trueMatchedSystems[result.id][key] = CrosswalkManager.trueMatchedSystems[result.id][key] || tmpTrueMatchedSystems[key]
67
+ # )
68
+ # )
69
+ # results
70
+ # )
71
+ # )
72
+ @instrumentTrueCrosswalk = instrumentTrueCrosswalk
@@ -131,7 +131,8 @@ class TS
131
131
 
132
132
  # Number of whole minutes between the two time stamps (as Date objects)
133
133
  @minutesDifference: (earlier, later) ->
134
- Math.floor(((later.getTime()-earlier.getTime())/1000)/60)
134
+ [e,l] = TS.dropSeconds(earlier,later)
135
+ Math.floor(((l.getTime()-e.getTime())/1000)/60)
135
136
 
136
137
  # Number of whole hours between the two time stamps (as Date objects)
137
138
  @hoursDifference: (earlier, later) ->
@@ -452,7 +453,8 @@ filterEventsByValue = (events, value) ->
452
453
  # Return only those events with a field that matches the supplied value
453
454
  filterEventsByField = (events, field, value) ->
454
455
  respondingEvents = (event for event in events when event.respondTo(field))
455
- result = (event for event in respondingEvents when value.match(event[field]()))
456
+ unit = value.unit() if value.unit?
457
+ result = (event for event in respondingEvents when value.match(event[field](unit)))
456
458
  hqmf.SpecificsManager.maintainSpecifics(result, events)
457
459
  @filterEventsByField = filterEventsByField
458
460
 
@@ -510,10 +512,13 @@ class CrossProduct extends Array
510
512
  constructor: (allEventLists) ->
511
513
  super()
512
514
  @eventLists = []
515
+ # keep track of the specific occurrences by encounter ID. This is used in eventsMatchBounds (specifically in buildRowsForMatching down the _.isObject path)
516
+ @specific_occurrence = {}
513
517
  for eventList in allEventLists
514
518
  @eventLists.push eventList
515
519
  for event in eventList
516
520
  this.push(event)
521
+ @specific_occurrence[event.id] = eventList.specific_occurrence if eventList.specific_occurrence
517
522
  listCount: -> @eventLists.length
518
523
  childList: (index) -> @eventLists[index]
519
524
 
@@ -525,9 +530,13 @@ XPRODUCT = (eventLists...) ->
525
530
  # Create a new list containing all the events from the supplied event lists
526
531
  UNION = (eventLists...) ->
527
532
  union = []
533
+ # keep track of the specific occurrences by encounter ID. This is used in eventsMatchBounds (specifically in buildRowsForMatching down the _.isObject path)
534
+ specific_occurrence = {}
528
535
  for eventList in eventLists
529
536
  for event in eventList
537
+ specific_occurrence[event.id] = eventList.specific_occurrence if eventList.specific_occurrence
530
538
  union.push(event)
539
+ union.specific_occurrence = specific_occurrence unless _.isEmpty(specific_occurrence)
531
540
  hqmf.SpecificsManager.unionAll(union, eventLists)
532
541
  @UNION = UNION
533
542
 
@@ -639,7 +648,7 @@ eventsMatchBounds = (events, bounds, methodName, range) ->
639
648
 
640
649
  if hasSpecificOccurrence
641
650
  matchingEvents.specific_occurrence = events.specific_occurrence
642
- # TODO: well need a temporary variable for non specific occurrences on the left so that we can do rejections based on restrictions in the data criteria
651
+ # we use a temporary variable for non specific occurrences on the left so that we can do rejections based on restrictions in the data criteria
643
652
  specificContext.addRows(Row.buildRowsForMatching(events.specific_occurrence, event, bounds.specific_occurrence, matchingBounds))
644
653
  else
645
654
  # add all stars
@@ -2,11 +2,13 @@ class @Logger
2
2
  @logger: []
3
3
  @rationale: {}
4
4
  @info: (string) ->
5
- @logger.push("#{Logger.indent()}#{string}")
5
+ if @enable_logging
6
+ @logger.push("#{Logger.indent()}#{string}")
6
7
  @record: (id, result) ->
7
- if result? and typeof(result.isTrue) == 'function'
8
+ if @enable_rationale and result? and typeof(result.isTrue) == 'function'
8
9
  @rationale[id] = result.isTrue()
9
- @enabled: true
10
+ @enable_logging: true
11
+ @enable_rationale: true
10
12
  @initialized: false
11
13
  @indentCount = 0
12
14
  @indent: ->
@@ -24,10 +26,10 @@ class @Logger
24
26
  else
25
27
  object
26
28
  @toJson: (value) ->
27
- if (typeof(tojson) == 'function')
28
- tojson(value)
29
- else
29
+ if (typeof(JSON) == 'object')
30
30
  JSON.stringify(value)
31
+ else
32
+ tojson(value)
31
33
  @classNameFor: (object) ->
32
34
  funcNameRegex = ///function (.+)\(///;
33
35
  results = funcNameRegex.exec(object.constructor.toString());
@@ -40,29 +42,61 @@ class @Logger
40
42
  memo.push("#{entry.codeSystemName()}:#{entry.code()}");
41
43
  memo
42
44
  , []).join(',')+"]"
45
+ @formatSpecificEntry: (object, index) ->
46
+ if object == hqmf.SpecificsManager.any
47
+ object
48
+ else
49
+ "#{object.id}"
50
+ @formatSpecificContext: (object) ->
51
+ displayRows = []
52
+ if object?.specificContext?.rows?.length
53
+ displayRows.push(Logger.toJson(item.id for item in hqmf.SpecificsManager.occurrences))
54
+ for row in object.specificContext.rows
55
+ do (row) ->
56
+ displayRow = []
57
+ for entry, index in row.values
58
+ do (entry) ->
59
+ displayRow.push(Logger.formatSpecificEntry(entry, index))
60
+ displayRows.push(Logger.toJson(displayRow))
61
+ displayRows
62
+ @logSpecificContext: (object) ->
63
+ Logger.indentCount++
64
+ for row in Logger.formatSpecificContext(object)
65
+ do (row) ->
66
+ Logger.info(row)
67
+ Logger.indentCount--
43
68
 
69
+
70
+ @injectLogger = (hqmfjs, enable_logging, enable_rationale) ->
71
+ Logger.enable_logging = enable_logging
72
+ Logger.enable_rationale = enable_rationale
44
73
 
45
- @enableMeasureLogging = (hqmfjs) ->
74
+ # Wrap all of the data criteria functions generated from HQMF
46
75
  _.each(_.functions(hqmfjs), (method) ->
47
- hqmfjs[method] = _.wrap(hqmfjs[method], (func) ->
76
+ if method != 'initializeSpecifics'
77
+ hqmfjs[method] = _.wrap(hqmfjs[method], (func) ->
48
78
 
49
- args = Array.prototype.slice.call(arguments,1)
79
+ args = Array.prototype.slice.call(arguments,1)
50
80
 
51
- Logger.info("#{method}:")
52
- Logger.indentCount++
53
- result = func.apply(this, args)
81
+ Logger.info("#{method}:")
82
+ Logger.indentCount++
83
+ result = func.apply(this, args)
54
84
 
55
- Logger.indentCount--
56
- Logger.info("#{method} -> #{Logger.asBoolean(result)}")
57
- Logger.record(method,result)
58
- return result;
59
- );
85
+ Logger.indentCount--
86
+ Logger.info("#{method} -> #{Logger.asBoolean(result)}")
87
+ if result.specificContext?.rows?.length
88
+ Logger.info("Specific context")
89
+ Logger.logSpecificContext(result)
90
+ Logger.info("------")
91
+ Logger.record(method,result)
92
+ return result;
93
+ );
60
94
  );
61
95
 
62
- @enableLogging =->
63
96
  if (!Logger.initialized)
64
97
  Logger.initialized=true
65
98
 
99
+ # Wrap selected hQuery Patient API functions
66
100
  _.each(_.functions(hQuery.Patient.prototype), (method) ->
67
101
  if (hQuery.Patient.prototype[method].length == 0)
68
102
  hQuery.Patient.prototype[method] = _.wrap(hQuery.Patient.prototype[method], (func) ->
@@ -88,6 +122,18 @@ class @Logger
88
122
  return result;
89
123
  );
90
124
 
125
+ # Wrap selected HQMF Util functions
126
+ hqmf.SpecificsManagerSingleton.prototype.intersectAll = _.wrap(hqmf.SpecificsManagerSingleton.prototype.intersectAll, (func, boolVal, values, negate=false, episodeIndices) ->
127
+ func = _.bind(func, this, boolVal, values, negate, episodeIndices)
128
+ result = func(boolVal, values, negate, episodeIndices)
129
+ Logger.info("Intersecting (#{values.length}):")
130
+ for value in values
131
+ Logger.logSpecificContext(value)
132
+ Logger.info("Intersected result:")
133
+ Logger.logSpecificContext(result)
134
+ return result;
135
+ );
136
+
91
137
  @getCodes = _.wrap(@getCodes, (func, oid) ->
92
138
  codes = func(oid)
93
139
  Logger.info("accessed codes: #{oid}")
@@ -127,6 +173,13 @@ class @Logger
127
173
  result
128
174
  )
129
175
 
176
+ @eventsMatchBounds = _.wrap(@eventsMatchBounds, (func, events, bounds, methodName, range) ->
177
+ args = Array.prototype.slice.call(arguments,1)
178
+ result = func(events, bounds, methodName, range)
179
+ Logger.info("#{methodName}(Events: #{Logger.stringify(events)}, Bounds: #{Logger.stringify(bounds)}, Range: #{Logger.toJson(range)}) -> #{Logger.stringify(result)}")
180
+ result
181
+ )
182
+
130
183
  @atLeastOneFalse = _.wrap(@atLeastOneFalse, (func) ->
131
184
  args = Array.prototype.slice.call(arguments,1)
132
185
  Logger.info("called atLeastOneFalse(#{args}):")
@@ -138,9 +191,3 @@ class @Logger
138
191
  result
139
192
  )
140
193
 
141
- @eventsMatchBounds = _.wrap(@eventsMatchBounds, (func, events, bounds, methodName, range) ->
142
- args = Array.prototype.slice.call(arguments,1)
143
- result = func(events, bounds, methodName, range)
144
- Logger.info("#{methodName}(Events: #{Logger.stringify(events)}, Bounds: #{Logger.stringify(bounds)}, Range: #{Logger.toJson(range)}) -> #{Logger.stringify(result)}")
145
- result
146
- )
@@ -18,6 +18,10 @@ hQuery.CodedEntry::asTS = ->
18
18
  ts.date = this.timeStamp()
19
19
  ts
20
20
 
21
+ hQuery.Encounter::lengthOfStay = (unit) ->
22
+ ivl_ts = this.asIVL_TS()
23
+ ivl_ts.low.difference(ivl_ts.high, unit)
24
+
21
25
  hQuery.CodedEntry::respondTo = (functionName) ->
22
26
  typeof(@[functionName]) == "function"
23
27
 
@@ -73,8 +73,13 @@ class hqmf.SpecificsManagerSingleton
73
73
  entry.specificRow = row
74
74
  entry
75
75
 
76
- intersectSpecifics: (populations...) ->
77
- value = @intersectAll(new Boolean(populations[0].isTrue()), populations)
76
+ intersectSpecifics: (nextPopulation, previousPopulation, occurrenceIDs) ->
77
+ # we need to pass the episode indicies all the way down through the interesection to the match function
78
+ # this must be done because we need to ensure that on intersection of populations the * does not allow an episode through
79
+ # that was not part of a previous population
80
+ episodeIndices = null
81
+ episodeIndices = (@getColumnIndex(occurrenceID) for occurrenceID in occurrenceIDs) if occurrenceIDs?
82
+ value = @intersectAll(new Boolean(nextPopulation.isTrue()), [nextPopulation, previousPopulation], false, episodeIndices)
78
83
  value
79
84
 
80
85
  # Returns a count of the unique events that match the criteria for the supplied
@@ -104,19 +109,19 @@ class hqmf.SpecificsManagerSingleton
104
109
  return @maintainSpecifics(new Boolean(false), initial)
105
110
  else
106
111
  return initial
107
-
112
+
108
113
  # Returns a boolean indication of whether all of the supplied population criteria are
109
114
  # met
110
115
  validate: (intersectedPopulation) ->
111
116
  intersectedPopulation.isTrue() and intersectedPopulation.specificContext.hasRows()
112
117
 
113
- intersectAll: (boolVal, values, negate=false) ->
118
+ intersectAll: (boolVal, values, negate=false, episodeIndices) ->
114
119
  result = new hqmf.SpecificOccurrence
115
120
  # add identity row
116
121
  result.addIdentityRow()
117
122
  for value in values
118
123
  if value.specificContext?
119
- result = result.intersect(value.specificContext)
124
+ result = result.intersect(value.specificContext, episodeIndices)
120
125
  if negate and (!result.hasRows() or result.hasSpecifics())
121
126
  result = result.negate()
122
127
  result = result.compactReusedEvents()
@@ -202,11 +207,11 @@ class hqmf.SpecificOccurrence
202
207
  value.rows = @rows.concat(other.rows)
203
208
  value.removeDuplicateRows()
204
209
 
205
- intersect: (other) ->
210
+ intersect: (other, episodeIndices) ->
206
211
  value = new hqmf.SpecificOccurrence()
207
212
  for leftRow in @rows
208
213
  for rightRow in other.rows
209
- result = leftRow.intersect(rightRow)
214
+ result = leftRow.intersect(rightRow, episodeIndices)
210
215
  value.rows.push(result) if result?
211
216
  value.removeDuplicateRows()
212
217
 
@@ -333,8 +338,6 @@ class hqmf.SpecificOccurrence
333
338
  addIdentityRow: ->
334
339
  @addRows(hqmf.SpecificsManager.identity().rows)
335
340
 
336
-
337
-
338
341
  class Row
339
342
  # {'OccurrenceAEncounter':1, 'OccurrenceBEncounter'2}
340
343
  constructor: (leftMost, occurrences={}) ->
@@ -370,18 +373,30 @@ class Row
370
373
  equal &&= Row.valuesEqual(value, other.values[i])
371
374
  equal
372
375
 
373
- intersect: (other) ->
376
+ intersect: (other, episodeIndices) ->
374
377
  intersectedRow = new Row(@leftMost, {})
375
378
  intersectedRow.tempValue = @tempValue
376
- allMatch = true
379
+
380
+ # if all the episodes are any, then they were not referenced by the parent population. This occurs when an intersection is done
381
+ # against the identity row. In this case we want to allow the specific occurrences through. This happens when we intersect against a measure
382
+ # without a denomninator, and on regular intersections since we start with the identity row in the context.
383
+ allEpisodesAny = (episodeIndices? && (@allValuesAny(episodeIndices) || other.allValuesAny(episodeIndices)))
384
+
377
385
  for value,i in @values
378
- result = Row.match(value, other.values[i])
386
+ # check if the value is an episode of care. If so it will be treated differently in the match function
387
+ isEpisodeOfCare = (episodeIndices? && !allEpisodesAny && episodeIndices.indexOf(i) >= 0)
388
+ result = Row.match(value, other.values[i], isEpisodeOfCare)
379
389
  if result?
380
390
  intersectedRow.values[i] = result
381
391
  else
382
392
  return undefined
383
393
  intersectedRow
384
394
 
395
+ allValuesAny: (indicies) ->
396
+ for i in indicies
397
+ return false if @values[i] != hqmf.SpecificsManager.any
398
+ return true
399
+
385
400
  groupKeyForLeftMost: ->
386
401
  @groupKey(@leftMost)
387
402
 
@@ -397,12 +412,20 @@ class Row
397
412
  keyForGroup
398
413
 
399
414
 
400
- @match: (left, right) ->
401
- return right if left == hqmf.SpecificsManager.any
402
- return left if right == hqmf.SpecificsManager.any
415
+ @match: (left, right, isEpisodeOfCare) ->
416
+ return @checkEpisodeOfCare(right, isEpisodeOfCare) if left == hqmf.SpecificsManager.any
417
+ return @checkEpisodeOfCare(left, isEpisodeOfCare) if right == hqmf.SpecificsManager.any
403
418
  return left if left.id == right.id
404
419
  return undefined
405
420
 
421
+ # if we are dealing with an episode of care we don't want to match against the any (*) indicator. This is because
422
+ # the any indicator from a previous population indicates that we did not evaluate against that occurrence in a positive path.
423
+ # this is typically OK with specific occurrences, but not if they represent episodes of care.
424
+ @checkEpisodeOfCare: (value, isEpisodeOfCare) ->
425
+ # return the any indicator to signify that the episode of care was unobserved. This will eliminate it from the counts.
426
+ return hqmf.SpecificsManager.any if (isEpisodeOfCare)
427
+ return value
428
+
406
429
  @valuesEqual: (left, right) ->
407
430
  return true if !left? and !right?
408
431
  return false if !left?
@@ -417,7 +440,12 @@ class Row
417
440
  for match in matches
418
441
  occurrences={}
419
442
  occurrences[entryKey] = entry
420
- occurrences[matchesKey] = match
443
+ # from unions and crossproducts we may have a matches key that is a hash of object ids mapped to the specific occurrence key.
444
+ # this is because we may have multiple different specific occurrences on the right hand side if it came from a group
445
+ if (_.isObject(matchesKey))
446
+ occurrences[matchesKey[match.id]] = match
447
+ else
448
+ occurrences[matchesKey] = match
421
449
  rows.push(new Row(entryKey, occurrences))
422
450
  rows
423
451
 
data/hqmf2js.gemspec CHANGED
@@ -7,15 +7,15 @@ Gem::Specification.new do |s|
7
7
  s.email = "hquery-talk@googlegroups.com"
8
8
  s.homepage = "http://github.com/hquery/hqmf2js"
9
9
  s.authors = ["Marc Hadley", "Andre Quina", "Andy Gregorowicz"]
10
- s.version = '1.2.0'
10
+ s.version = '1.2.1'
11
11
 
12
12
  s.add_dependency 'nokogiri', '~> 1.5.5'
13
13
  s.add_dependency 'tilt', '~> 1.3.3'
14
14
  s.add_dependency 'coffee-script', '~> 2.2.0'
15
15
  s.add_dependency 'sprockets', '~> 2.2.2'
16
16
  s.add_development_dependency "awesome_print", "~> 1.1.0"
17
- s.add_dependency 'health-data-standards', '~> 3.0.1'
18
- s.add_dependency 'hquery-patient-api', '~> 1.0.1'
17
+ s.add_dependency 'health-data-standards', '~> 3.1.1'
18
+ s.add_dependency 'hquery-patient-api', '~> 1.0.2'
19
19
 
20
20
  s.files = s.files = `git ls-files`.split("\n")
21
21
  end
@@ -1,4 +1,4 @@
1
- var value = patient.<%= criteria.property %>(<%= js_for_date_bound(criteria) if criteria.property == :age %>);
1
+ var value = patient.<%= criteria.property %>(<%= js_for_date_bound(criteria) if criteria.property == :age %>) || null;
2
2
  <%- if criteria.property == :birthtime -%>
3
3
  var events = [value];
4
4
  <%- if criteria.temporal_references -%>
@@ -1,10 +1,6 @@
1
1
  module HQMF2JS
2
2
  module Generator
3
3
  class CodesToJson
4
- def self.from_xls(code_systems_file)
5
- value_sets = HQMF::ValueSet::Parser.new().parse(code_systems_file)
6
- from_value_sets(value_sets)
7
- end
8
4
 
9
5
  def self.hash_to_js(hash)
10
6
  hash.to_json.gsub(/\"/, "'")
data/lib/generator/js.rb CHANGED
@@ -240,25 +240,33 @@ module HQMF2JS
240
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})
241
241
  end
242
242
 
243
- def self.library_functions
243
+ def self.library_functions(check_crosswalk=false)
244
244
  ctx = Sprockets::Environment.new(File.expand_path("../../..", __FILE__))
245
245
  Tilt::CoffeeScriptTemplate.default_bare = true
246
246
  ctx.append_path "app/assets/javascripts"
247
247
 
248
- ["// #########################\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].join("\n")
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]
262
+
263
+ # check for code set crosswalks
264
+ if (check_crosswalk)
265
+ libraries += ["// #########################\n// ##### CROSSWALK EXTENSION ######\n// #########################\n",
266
+ ctx.find_asset('crosswalk').to_s]
267
+ end
268
+
269
+ libraries.join("\n")
262
270
 
263
271
  end
264
272
 
@@ -20,19 +20,5 @@ class CodesToJsonTest < Test::Unit::TestCase
20
20
 
21
21
  end
22
22
 
23
- def test_parsing_from_xls
24
-
25
- codes_file_path = File.expand_path("../../fixtures/codes/codes.xls", __FILE__)
26
- # Parse the code systems that are mapped to the OIDs we support
27
- codes_json = HQMF2JS::Generator::CodesToJson.hash_to_js(HQMF2JS::Generator::CodesToJson.from_xls(codes_file_path))
28
-
29
- @context = get_js_context("var dictionary = #{codes_json}")
30
- @context.eval("dictionary").entries.length.must_equal 12
31
- @context.eval("dictionary['2.16.840.1.113883.3.464.0001.430']").entries.first[0].must_equal "RxNorm"
32
- @context.eval("dictionary['2.16.840.1.113883.3.464.0001.430']").entries.first[1].length.must_equal 25
33
-
34
- end
35
-
36
-
37
23
 
38
24
  end
@@ -178,6 +178,14 @@ class LibraryFunctionTest < Test::Unit::TestCase
178
178
  ts2 = 'new TS("201203010020")'
179
179
  assert_equal 70, @context.eval("#{ts1}.difference(#{ts2},'min')")
180
180
 
181
+ ts1 = 'new TS("20120101101010")'
182
+ ts2 = 'new TS("20120101101030")'
183
+ assert_equal 0, @context.eval("#{ts1}.difference(#{ts2},'min')")
184
+
185
+ ts1 = 'new TS("20120101100950")'
186
+ ts2 = 'new TS("20120101101010")'
187
+ assert_equal 1, @context.eval("#{ts1}.difference(#{ts2},'min')")
188
+
181
189
  # Additional tests from previous version of TJC guidance
182
190
  ts4 = 'new TS("20000310")'
183
191
  ts5 = 'new TS("20110405")'
@@ -19,7 +19,7 @@ class SpecificsTest < Test::Unit::TestCase
19
19
  end
20
20
 
21
21
 
22
- def test_specifics_initialized_proper
22
+ def test_specifics_initialized_properly
23
23
 
24
24
  @context.eval('hqmf.SpecificsManager.keyLookup[0]').must_equal 'OccurrenceAEncounter'
25
25
  @context.eval('hqmf.SpecificsManager.keyLookup[1]').must_equal 'OccurrenceBEncounter'
@@ -593,12 +593,100 @@ class SpecificsTest < Test::Unit::TestCase
593
593
  "
594
594
  @context.eval(rows)
595
595
 
596
- @context.eval('hqmf.SpecificsManager.validate(hqmf.SpecificsManager.intersectSpecifics(pop1,pop2,pop3))').must_equal true
597
- @context.eval('hqmf.SpecificsManager.validate(hqmf.SpecificsManager.intersectSpecifics(pop1,pop2,pop4))').must_equal false
598
- @context.eval('hqmf.SpecificsManager.validate(hqmf.SpecificsManager.intersectSpecifics(pop1,pop2,pop5))').must_equal false
599
- @context.eval('hqmf.SpecificsManager.validate(hqmf.SpecificsManager.intersectSpecifics(pop3f,pop1,pop2))').must_equal false
596
+ @context.eval('hqmf.SpecificsManager.validate(hqmf.SpecificsManager.intersectSpecifics(pop1, hqmf.SpecificsManager.intersectSpecifics(pop2,pop3)))').must_equal true
597
+ @context.eval('hqmf.SpecificsManager.validate(hqmf.SpecificsManager.intersectSpecifics(pop1, hqmf.SpecificsManager.intersectSpecifics(pop2,pop4)))').must_equal false
598
+ @context.eval('hqmf.SpecificsManager.validate(hqmf.SpecificsManager.intersectSpecifics(pop1, hqmf.SpecificsManager.intersectSpecifics(pop2,pop5)))').must_equal false
599
+ @context.eval('hqmf.SpecificsManager.validate(hqmf.SpecificsManager.intersectSpecifics(pop3f,hqmf.SpecificsManager.intersectSpecifics(pop1,pop2)))').must_equal false
600
600
 
601
601
  end
602
+
603
+ def test_episode_of_care_restrictions
604
+
605
+ rows = "
606
+ hqmf.SpecificsManager.initialize({},hqmfjs, {'id':'OccurrenceAEncounter1', 'type':'Encounter', 'function':'SourceOccurrenceAEncounter1'},
607
+ {'id':'OccurrenceAEncounter2', 'type':'Encounter', 'function':'SourceOccurrenceAEncounter2'},
608
+ {'id':'OccurrenceAEncounter3', 'type':'Encounter', 'function':'SourceOccurrenceAEncounter3'})
609
+
610
+
611
+ var row1 = new Row('OccurrenceAEncounter1',{'OccurrenceAEncounter1':{'id':1}});
612
+ var row2 = new Row('OccurrenceAEncounter2',{'OccurrenceAEncounter2':{'id':3}});
613
+ var row3 = new Row('OccurrenceAEncounter1',{'OccurrenceAEncounter1':{'id':1},'OccurrenceAEncounter2':{'id':3}});
614
+ var identityRow = hqmf.SpecificsManager.identity().rows[0];
615
+
616
+ var pop1 = new Boolean(true);
617
+ var pop2 = new Boolean(true);
618
+ var pop3 = new Boolean(true);
619
+ var pop4 = new Boolean(true);
620
+
621
+ pop1.specificContext = new hqmf.SpecificOccurrence([row1]);
622
+ pop2.specificContext = new hqmf.SpecificOccurrence([row2]);
623
+ pop3.specificContext = new hqmf.SpecificOccurrence([row3]);
624
+ pop4.specificContext = new hqmf.SpecificOccurrence([identityRow]);
625
+
626
+ var result = null;
627
+
628
+ "
629
+ @context.eval(rows)
630
+
631
+ # test allValuesAny
632
+ @context.eval('row1.allValuesAny([0,1,2])').must_equal false
633
+ @context.eval('row1.allValuesAny([1,2])').must_equal true
634
+ @context.eval('row1.allValuesAny([2])').must_equal true
635
+ @context.eval('row1.allValuesAny([1])').must_equal true
636
+ @context.eval('row1.allValuesAny([])').must_equal true
637
+ @context.eval('identityRow.allValuesAny([0,1,2])').must_equal true
638
+
639
+ # test checkEpisodeOfCare
640
+ @context.eval('Row.checkEpisodeOfCare({id: 1}, true) == hqmf.SpecificsManager.any').must_equal true
641
+ @context.eval('Row.checkEpisodeOfCare({id: 1}, false) == hqmf.SpecificsManager.any').must_equal false
642
+ @context.eval('Row.checkEpisodeOfCare({id: 1}, false).id == 1').must_equal true
643
+
644
+ # test intersect
645
+ @context.eval('row1.intersect(row2,[0,1]).allValuesAny([0,1,2])').must_equal true # this is the critical check. Make sure we drop bad episode of care intersections
646
+ @context.eval('row1.intersect(row2,[0]).allValuesAny([2])').must_equal true
647
+ @context.eval('row1.intersect(row2,[0]).values[0].id == 1').must_equal true
648
+ @context.eval('row1.intersect(row2,[0]).values[1].id == 3').must_equal true
649
+ @context.eval('row1.intersect(row2,[1]).allValuesAny([2])').must_equal true
650
+ @context.eval('row1.intersect(row2,[1]).values[0].id == 1').must_equal true
651
+ @context.eval('row1.intersect(row2,[1]).values[1].id == 3').must_equal true
652
+
653
+ @context.eval('identityRow.intersect(row1,[0]).values[0].id == 1').must_equal true
654
+ @context.eval('identityRow.intersect(row1,[0]).allValuesAny([1,2])').must_equal true
655
+ @context.eval('row1.intersect(identityRow,[0]).values[0].id == 1').must_equal true
656
+ @context.eval('row1.intersect(identityRow,[0]).allValuesAny([1,2])').must_equal true
657
+
658
+ # make sure we drop a bad strggler for encounter 2
659
+ @context.eval('row1.intersect(row3,[0,1]).allValuesAny([1,2])').must_equal true
660
+ @context.eval('row1.intersect(row3,[0,1]).values[0].id == 1').must_equal true
661
+
662
+ # test intersectSpecifics
663
+
664
+ @context.eval('hqmf.SpecificsManager.intersectSpecifics(pop1,pop2).specificContext.rows[0].values[0].id == 1').must_equal true
665
+ @context.eval('hqmf.SpecificsManager.intersectSpecifics(pop1,pop2).specificContext.rows[0].values[1].id == 3').must_equal true
666
+ @context.eval('hqmf.SpecificsManager.intersectSpecifics(pop1,pop2).specificContext.rows[0].values[2] == hqmf.SpecificsManager.any').must_equal true
667
+ @context.eval("hqmf.SpecificsManager.intersectSpecifics(pop1,pop2,['OccurrenceAEncounter1','OccurrenceAEncounter2','OccurrenceAEncounter3']).specificContext.rows[0].allValuesAny([0,1,2])").must_equal true
668
+ @context.eval("result = hqmf.SpecificsManager.intersectSpecifics(pop1,pop2,['OccurrenceAEncounter1']).specificContext.rows[0]")
669
+ @context.eval('result.allValuesAny([2])').must_equal true
670
+ @context.eval('result.values[0].id == 1').must_equal true
671
+ @context.eval('result.values[1].id == 3').must_equal true
672
+ @context.eval("result = hqmf.SpecificsManager.intersectSpecifics(pop1,pop2,['OccurrenceAEncounter2']).specificContext.rows[0]")
673
+ @context.eval('result.allValuesAny([2])').must_equal true
674
+ @context.eval('result.values[0].id == 1').must_equal true
675
+ @context.eval('result.values[1].id == 3').must_equal true
676
+
677
+ @context.eval("result = hqmf.SpecificsManager.intersectSpecifics(pop1,pop4,['OccurrenceAEncounter1']).specificContext.rows[0]")
678
+ @context.eval('result.values[0].id == 1').must_equal true
679
+ @context.eval('result.allValuesAny([1,2])').must_equal true
680
+
681
+ @context.eval("result = hqmf.SpecificsManager.intersectSpecifics(pop4,pop1,['OccurrenceAEncounter1']).specificContext.rows[0]")
682
+ @context.eval('result.values[0].id == 1').must_equal true
683
+ @context.eval('result.allValuesAny([1,2])').must_equal true
684
+
685
+ @context.eval("result = hqmf.SpecificsManager.intersectSpecifics(pop1,pop3,['OccurrenceAEncounter1','OccurrenceAEncounter2']).specificContext.rows[0]")
686
+ @context.eval('result.allValuesAny([1,2])').must_equal true
687
+ @context.eval('result.values[0].id == 1').must_equal true
688
+
689
+ end
602
690
 
603
691
  def test_intersect_all
604
692
 
@@ -774,20 +862,20 @@ class SpecificsTest < Test::Unit::TestCase
774
862
  "
775
863
  @context.eval(rows)
776
864
  @context.eval('hqmf.SpecificsManager.extractEvents(undefined, non_specific_rows).length').must_equal 6
777
- @context.eval('hqmf.SpecificsManager.extractEvents(undefined, non_specific_rows)[0].id').must_equal 10
778
- @context.eval('hqmf.SpecificsManager.extractEvents(undefined, non_specific_rows)[1].id').must_equal 11
779
- @context.eval('hqmf.SpecificsManager.extractEvents(undefined, non_specific_rows)[2].id').must_equal 12
780
- @context.eval('hqmf.SpecificsManager.extractEvents(undefined, non_specific_rows)[3].id').must_equal 13
781
- @context.eval('hqmf.SpecificsManager.extractEvents(undefined, non_specific_rows)[4].id').must_equal 14
782
- @context.eval('hqmf.SpecificsManager.extractEvents(undefined, non_specific_rows)[5].id').must_equal 15
865
+ @context.eval('hqmf.SpecificsManager.extractEvents(undefined, non_specific_rows)[0].id').must_equal '10'
866
+ @context.eval('hqmf.SpecificsManager.extractEvents(undefined, non_specific_rows)[1].id').must_equal '11'
867
+ @context.eval('hqmf.SpecificsManager.extractEvents(undefined, non_specific_rows)[2].id').must_equal '12'
868
+ @context.eval('hqmf.SpecificsManager.extractEvents(undefined, non_specific_rows)[3].id').must_equal '13'
869
+ @context.eval('hqmf.SpecificsManager.extractEvents(undefined, non_specific_rows)[4].id').must_equal '14'
870
+ @context.eval('hqmf.SpecificsManager.extractEvents(undefined, non_specific_rows)[5].id').must_equal '15'
783
871
 
784
872
  @context.eval("hqmf.SpecificsManager.extractEvents('OccurrenceAEncounter', specific_rows).length").must_equal 6
785
- @context.eval("hqmf.SpecificsManager.extractEvents('OccurrenceAEncounter', specific_rows)[0].id").must_equal 10
786
- @context.eval("hqmf.SpecificsManager.extractEvents('OccurrenceAEncounter', specific_rows)[1].id").must_equal 11
787
- @context.eval("hqmf.SpecificsManager.extractEvents('OccurrenceAEncounter', specific_rows)[2].id").must_equal 12
788
- @context.eval("hqmf.SpecificsManager.extractEvents('OccurrenceAEncounter', specific_rows)[3].id").must_equal 13
789
- @context.eval("hqmf.SpecificsManager.extractEvents('OccurrenceAEncounter', specific_rows)[4].id").must_equal 14
790
- @context.eval("hqmf.SpecificsManager.extractEvents('OccurrenceAEncounter', specific_rows)[5].id").must_equal 15
873
+ @context.eval("hqmf.SpecificsManager.extractEvents('OccurrenceAEncounter', specific_rows)[0].id").must_equal '10'
874
+ @context.eval("hqmf.SpecificsManager.extractEvents('OccurrenceAEncounter', specific_rows)[1].id").must_equal '11'
875
+ @context.eval("hqmf.SpecificsManager.extractEvents('OccurrenceAEncounter', specific_rows)[2].id").must_equal '12'
876
+ @context.eval("hqmf.SpecificsManager.extractEvents('OccurrenceAEncounter', specific_rows)[3].id").must_equal '13'
877
+ @context.eval("hqmf.SpecificsManager.extractEvents('OccurrenceAEncounter', specific_rows)[4].id").must_equal '14'
878
+ @context.eval("hqmf.SpecificsManager.extractEvents('OccurrenceAEncounter', specific_rows)[5].id").must_equal '15'
791
879
 
792
880
  end
793
881
 
@@ -830,30 +918,30 @@ class SpecificsTest < Test::Unit::TestCase
830
918
  exactly1 = 'new IVL_PQ(new PQ(1), new PQ(1))'
831
919
 
832
920
  @context.eval("specific1.COUNT(#{moreThanOne}).rows.length").must_equal 5
833
- @context.eval("specific1.COUNT(#{moreThanOne}).rows[0].tempValue.id").must_equal 10
834
- @context.eval("specific1.COUNT(#{moreThanOne}).rows[1].tempValue.id").must_equal 11
835
- @context.eval("specific1.COUNT(#{moreThanOne}).rows[2].tempValue.id").must_equal 12
836
- @context.eval("specific1.COUNT(#{moreThanOne}).rows[3].tempValue.id").must_equal 13
837
- @context.eval("specific1.COUNT(#{moreThanOne}).rows[4].tempValue.id").must_equal 14
921
+ @context.eval("specific1.COUNT(#{moreThanOne}).rows[0].tempValue.id").must_equal '10'
922
+ @context.eval("specific1.COUNT(#{moreThanOne}).rows[1].tempValue.id").must_equal '11'
923
+ @context.eval("specific1.COUNT(#{moreThanOne}).rows[2].tempValue.id").must_equal '12'
924
+ @context.eval("specific1.COUNT(#{moreThanOne}).rows[3].tempValue.id").must_equal '13'
925
+ @context.eval("specific1.COUNT(#{moreThanOne}).rows[4].tempValue.id").must_equal '14'
838
926
  @context.eval("specific1.COUNT(#{lessThanThree}).rows.length").must_equal 3
839
- @context.eval("specific1.COUNT(#{lessThanThree}).rows[0].tempValue.id").must_equal 10
840
- @context.eval("specific1.COUNT(#{lessThanThree}).rows[1].tempValue.id").must_equal 11
841
- @context.eval("specific1.COUNT(#{lessThanThree}).rows[2].tempValue.id").must_equal 15
927
+ @context.eval("specific1.COUNT(#{lessThanThree}).rows[0].tempValue.id").must_equal '10'
928
+ @context.eval("specific1.COUNT(#{lessThanThree}).rows[1].tempValue.id").must_equal '11'
929
+ @context.eval("specific1.COUNT(#{lessThanThree}).rows[2].tempValue.id").must_equal '15'
842
930
  @context.eval("specific1.COUNT(#{exactly1}).rows.length").must_equal 1
843
- @context.eval("specific1.COUNT(#{exactly1}).rows[0].tempValue.id").must_equal 15
931
+ @context.eval("specific1.COUNT(#{exactly1}).rows[0].tempValue.id").must_equal '15'
844
932
 
845
933
  @context.eval("specific2.COUNT(#{moreThanOne}).rows.length").must_equal 5
846
- @context.eval("specific2.COUNT(#{moreThanOne}).rows[0].values[0].id").must_equal 10
847
- @context.eval("specific2.COUNT(#{moreThanOne}).rows[1].values[0].id").must_equal 11
848
- @context.eval("specific2.COUNT(#{moreThanOne}).rows[2].values[0].id").must_equal 12
849
- @context.eval("specific2.COUNT(#{moreThanOne}).rows[3].values[0].id").must_equal 13
850
- @context.eval("specific2.COUNT(#{moreThanOne}).rows[4].values[0].id").must_equal 14
934
+ @context.eval("specific2.COUNT(#{moreThanOne}).rows[0].values[0].id").must_equal '10'
935
+ @context.eval("specific2.COUNT(#{moreThanOne}).rows[1].values[0].id").must_equal '11'
936
+ @context.eval("specific2.COUNT(#{moreThanOne}).rows[2].values[0].id").must_equal '12'
937
+ @context.eval("specific2.COUNT(#{moreThanOne}).rows[3].values[0].id").must_equal '13'
938
+ @context.eval("specific2.COUNT(#{moreThanOne}).rows[4].values[0].id").must_equal '14'
851
939
  @context.eval("specific2.COUNT(#{lessThanThree}).rows.length").must_equal 3
852
- @context.eval("specific2.COUNT(#{lessThanThree}).rows[0].values[0].id").must_equal 10
853
- @context.eval("specific2.COUNT(#{lessThanThree}).rows[1].values[0].id").must_equal 11
854
- @context.eval("specific2.COUNT(#{lessThanThree}).rows[2].values[0].id").must_equal 15
940
+ @context.eval("specific2.COUNT(#{lessThanThree}).rows[0].values[0].id").must_equal '10'
941
+ @context.eval("specific2.COUNT(#{lessThanThree}).rows[1].values[0].id").must_equal '11'
942
+ @context.eval("specific2.COUNT(#{lessThanThree}).rows[2].values[0].id").must_equal '15'
855
943
  @context.eval("specific2.COUNT(#{exactly1}).rows.length").must_equal 1
856
- @context.eval("specific2.COUNT(#{exactly1}).rows[0].values[0].id").must_equal 15
944
+ @context.eval("specific2.COUNT(#{exactly1}).rows[0].values[0].id").must_equal '15'
857
945
 
858
946
  @context.eval("specific3.COUNT(#{exactly1}).rows.length").must_equal 1
859
947
  @context.eval("specific4.COUNT(#{moreThanOne}).rows.length").must_equal 0
@@ -863,14 +951,14 @@ class SpecificsTest < Test::Unit::TestCase
863
951
  ##### FIRST
864
952
  ###
865
953
  @context.eval("specific1.FIRST().rows.length").must_equal 3
866
- @context.eval("specific1.FIRST().rows[0].tempValue.id").must_equal 11
867
- @context.eval("specific1.FIRST().rows[1].tempValue.id").must_equal 12
868
- @context.eval("specific1.FIRST().rows[2].tempValue.id").must_equal 15
954
+ @context.eval("specific1.FIRST().rows[0].tempValue.id").must_equal '11'
955
+ @context.eval("specific1.FIRST().rows[1].tempValue.id").must_equal '12'
956
+ @context.eval("specific1.FIRST().rows[2].tempValue.id").must_equal '15'
869
957
 
870
958
  @context.eval("specific2.FIRST().rows.length").must_equal 3
871
- @context.eval("specific2.FIRST().rows[0].values[0].id").must_equal 11
872
- @context.eval("specific2.FIRST().rows[1].values[0].id").must_equal 12
873
- @context.eval("specific2.FIRST().rows[2].values[0].id").must_equal 15
959
+ @context.eval("specific2.FIRST().rows[0].values[0].id").must_equal '11'
960
+ @context.eval("specific2.FIRST().rows[1].values[0].id").must_equal '12'
961
+ @context.eval("specific2.FIRST().rows[2].values[0].id").must_equal '15'
874
962
 
875
963
  @context.eval("specific3.FIRST().rows.length").must_equal 1
876
964
  @context.eval("specific4.FIRST().rows.length").must_equal 0
@@ -880,14 +968,14 @@ class SpecificsTest < Test::Unit::TestCase
880
968
  ###
881
969
 
882
970
  @context.eval("specific1.RECENT().rows.length").must_equal 3
883
- @context.eval("specific1.RECENT().rows[0].tempValue.id").must_equal 10
884
- @context.eval("specific1.RECENT().rows[1].tempValue.id").must_equal 13
885
- @context.eval("specific1.RECENT().rows[2].tempValue.id").must_equal 15
971
+ @context.eval("specific1.RECENT().rows[0].tempValue.id").must_equal '10'
972
+ @context.eval("specific1.RECENT().rows[1].tempValue.id").must_equal '13'
973
+ @context.eval("specific1.RECENT().rows[2].tempValue.id").must_equal '15'
886
974
 
887
975
  @context.eval("specific2.RECENT().rows.length").must_equal 3
888
- @context.eval("specific2.RECENT().rows[0].values[0].id").must_equal 10
889
- @context.eval("specific2.RECENT().rows[1].values[0].id").must_equal 13
890
- @context.eval("specific2.RECENT().rows[2].values[0].id").must_equal 15
976
+ @context.eval("specific2.RECENT().rows[0].values[0].id").must_equal '10'
977
+ @context.eval("specific2.RECENT().rows[1].values[0].id").must_equal '13'
978
+ @context.eval("specific2.RECENT().rows[2].values[0].id").must_equal '15'
891
979
 
892
980
  @context.eval("specific3.RECENT().rows.length").must_equal 1
893
981
  @context.eval("specific4.RECENT().rows.length").must_equal 0
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hqmf2js
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.2.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2013-02-27 00:00:00.000000000 Z
14
+ date: 2013-04-23 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: nokogiri
@@ -100,7 +100,7 @@ dependencies:
100
100
  requirements:
101
101
  - - ~>
102
102
  - !ruby/object:Gem::Version
103
- version: 3.0.1
103
+ version: 3.1.1
104
104
  type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
@@ -108,7 +108,7 @@ dependencies:
108
108
  requirements:
109
109
  - - ~>
110
110
  - !ruby/object:Gem::Version
111
- version: 3.0.1
111
+ version: 3.1.1
112
112
  - !ruby/object:Gem::Dependency
113
113
  name: hquery-patient-api
114
114
  requirement: !ruby/object:Gem::Requirement
@@ -116,7 +116,7 @@ dependencies:
116
116
  requirements:
117
117
  - - ~>
118
118
  - !ruby/object:Gem::Version
119
- version: 1.0.1
119
+ version: 1.0.2
120
120
  type: :runtime
121
121
  prerelease: false
122
122
  version_requirements: !ruby/object:Gem::Requirement
@@ -124,7 +124,7 @@ dependencies:
124
124
  requirements:
125
125
  - - ~>
126
126
  - !ruby/object:Gem::Version
127
- version: 1.0.1
127
+ version: 1.0.2
128
128
  description: A library for converting HQMF files to executable JavaScript suitable
129
129
  for use with the hQuery Gateway
130
130
  email: hquery-talk@googlegroups.com
@@ -139,6 +139,7 @@ files:
139
139
  - README.md
140
140
  - Rakefile
141
141
  - VERSION
142
+ - app/assets/javascripts/crosswalk.js.coffee
142
143
  - app/assets/javascripts/custom_calculations.js.coffee
143
144
  - app/assets/javascripts/hqmf_util.js.coffee
144
145
  - app/assets/javascripts/logging_utils.js.coffee