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 +1 -1
- data/Gemfile.lock +9 -42
- data/app/assets/javascripts/crosswalk.js.coffee +72 -0
- data/app/assets/javascripts/hqmf_util.js.coffee +12 -3
- data/app/assets/javascripts/logging_utils.js.coffee +71 -24
- data/app/assets/javascripts/patient_api_extension.js.coffee +4 -0
- data/app/assets/javascripts/specifics.js.coffee +44 -16
- data/hqmf2js.gemspec +3 -3
- data/lib/generator/characteristic.js.erb +1 -1
- data/lib/generator/codes_to_json.rb +0 -4
- data/lib/generator/js.rb +23 -15
- data/test/unit/codes_to_json_test.rb +0 -14
- data/test/unit/library_function_test.rb +8 -0
- data/test/unit/specifics_test.rb +135 -47
- metadata +7 -6
data/.travis.yml
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
hqmf2js (1.2.
|
4
|
+
hqmf2js (1.2.1)
|
5
5
|
coffee-script (~> 2.2.0)
|
6
|
-
health-data-standards (~> 3.
|
7
|
-
hquery-patient-api (~> 1.0.
|
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.
|
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.
|
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.
|
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.
|
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
|
-
|
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
|
-
|
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
|
-
#
|
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
|
-
@
|
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
|
-
@
|
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(
|
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
|
-
|
74
|
+
# Wrap all of the data criteria functions generated from HQMF
|
46
75
|
_.each(_.functions(hqmfjs), (method) ->
|
47
|
-
|
76
|
+
if method != 'initializeSpecifics'
|
77
|
+
hqmfjs[method] = _.wrap(hqmfjs[method], (func) ->
|
48
78
|
|
49
|
-
|
79
|
+
args = Array.prototype.slice.call(arguments,1)
|
50
80
|
|
51
|
-
|
52
|
-
|
53
|
-
|
81
|
+
Logger.info("#{method}:")
|
82
|
+
Logger.indentCount++
|
83
|
+
result = func.apply(this, args)
|
54
84
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
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: (
|
77
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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.
|
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.
|
18
|
-
s.add_dependency 'hquery-patient-api', '~> 1.0.
|
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 -%>
|
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
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
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")'
|
data/test/unit/specifics_test.rb
CHANGED
@@ -19,7 +19,7 @@ class SpecificsTest < Test::Unit::TestCase
|
|
19
19
|
end
|
20
20
|
|
21
21
|
|
22
|
-
def
|
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.
|
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-
|
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.
|
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.
|
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.
|
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.
|
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
|