app/assets/javascripts/specifics.js.coffee in hqmf2js-1.2.0 vs app/assets/javascripts/specifics.js.coffee in hqmf2js-1.2.1
- old
+ new
@@ -71,12 +71,17 @@
entry = row.tempValue
entry = new hQuery.CodedEntry(entry.json)
entry.specificRow = row
entry
- intersectSpecifics: (populations...) ->
- value = @intersectAll(new Boolean(populations[0].isTrue()), populations)
+ intersectSpecifics: (nextPopulation, previousPopulation, occurrenceIDs) ->
+ # we need to pass the episode indicies all the way down through the interesection to the match function
+ # this must be done because we need to ensure that on intersection of populations the * does not allow an episode through
+ # that was not part of a previous population
+ episodeIndices = null
+ episodeIndices = (@getColumnIndex(occurrenceID) for occurrenceID in occurrenceIDs) if occurrenceIDs?
+ value = @intersectAll(new Boolean(nextPopulation.isTrue()), [nextPopulation, previousPopulation], false, episodeIndices)
value
# Returns a count of the unique events that match the criteria for the supplied
# specific occurrence. Call after validating that population criteria are met. Returns
# 1 if occurrenceID is null, for use with patient based measures.
@@ -102,23 +107,23 @@
return result
else if @validate(exclusions)
return @maintainSpecifics(new Boolean(false), initial)
else
return initial
-
+
# Returns a boolean indication of whether all of the supplied population criteria are
# met
validate: (intersectedPopulation) ->
intersectedPopulation.isTrue() and intersectedPopulation.specificContext.hasRows()
- intersectAll: (boolVal, values, negate=false) ->
+ intersectAll: (boolVal, values, negate=false, episodeIndices) ->
result = new hqmf.SpecificOccurrence
# add identity row
result.addIdentityRow()
for value in values
if value.specificContext?
- result = result.intersect(value.specificContext)
+ result = result.intersect(value.specificContext, episodeIndices)
if negate and (!result.hasRows() or result.hasSpecifics())
result = result.negate()
result = result.compactReusedEvents()
# this is a little odd, but it appears when we have a negation with specifics we can
# ignore the logical result of the negation. The reason we do this is because we may
@@ -200,15 +205,15 @@
union: (other) ->
value = new hqmf.SpecificOccurrence()
value.rows = @rows.concat(other.rows)
value.removeDuplicateRows()
- intersect: (other) ->
+ intersect: (other, episodeIndices) ->
value = new hqmf.SpecificOccurrence()
for leftRow in @rows
for rightRow in other.rows
- result = leftRow.intersect(rightRow)
+ result = leftRow.intersect(rightRow, episodeIndices)
value.rows.push(result) if result?
value.removeDuplicateRows()
getLeftMost: ->
leftMost = undefined
@@ -331,12 +336,10 @@
new hqmf.SpecificOccurrence(resultRows)
addIdentityRow: ->
@addRows(hqmf.SpecificsManager.identity().rows)
-
-
class Row
# {'OccurrenceAEncounter':1, 'OccurrenceBEncounter'2}
constructor: (leftMost, occurrences={}) ->
throw "left most key must be a string or undefined was: #{leftMost}" if typeof(leftMost) != 'string' and typeof(leftMost) != 'undefined'
@length = hqmf.SpecificsManager.occurrences.length
@@ -368,22 +371,34 @@
equal &&= Row.valuesEqual(@tempValue, other.tempValue)
for value,i in @values
equal &&= Row.valuesEqual(value, other.values[i])
equal
- intersect: (other) ->
+ intersect: (other, episodeIndices) ->
intersectedRow = new Row(@leftMost, {})
intersectedRow.tempValue = @tempValue
- allMatch = true
+
+ # if all the episodes are any, then they were not referenced by the parent population. This occurs when an intersection is done
+ # against the identity row. In this case we want to allow the specific occurrences through. This happens when we intersect against a measure
+ # without a denomninator, and on regular intersections since we start with the identity row in the context.
+ allEpisodesAny = (episodeIndices? && (@allValuesAny(episodeIndices) || other.allValuesAny(episodeIndices)))
+
for value,i in @values
- result = Row.match(value, other.values[i])
+ # check if the value is an episode of care. If so it will be treated differently in the match function
+ isEpisodeOfCare = (episodeIndices? && !allEpisodesAny && episodeIndices.indexOf(i) >= 0)
+ result = Row.match(value, other.values[i], isEpisodeOfCare)
if result?
intersectedRow.values[i] = result
else
return undefined
intersectedRow
+ allValuesAny: (indicies) ->
+ for i in indicies
+ return false if @values[i] != hqmf.SpecificsManager.any
+ return true
+
groupKeyForLeftMost: ->
@groupKey(@leftMost)
groupKey: (key=null) ->
keyForGroup = ''
@@ -395,16 +410,24 @@
else
keyForGroup += "#{value}_"
keyForGroup
- @match: (left, right) ->
- return right if left == hqmf.SpecificsManager.any
- return left if right == hqmf.SpecificsManager.any
+ @match: (left, right, isEpisodeOfCare) ->
+ return @checkEpisodeOfCare(right, isEpisodeOfCare) if left == hqmf.SpecificsManager.any
+ return @checkEpisodeOfCare(left, isEpisodeOfCare) if right == hqmf.SpecificsManager.any
return left if left.id == right.id
return undefined
+ # if we are dealing with an episode of care we don't want to match against the any (*) indicator. This is because
+ # the any indicator from a previous population indicates that we did not evaluate against that occurrence in a positive path.
+ # this is typically OK with specific occurrences, but not if they represent episodes of care.
+ @checkEpisodeOfCare: (value, isEpisodeOfCare) ->
+ # return the any indicator to signify that the episode of care was unobserved. This will eliminate it from the counts.
+ return hqmf.SpecificsManager.any if (isEpisodeOfCare)
+ return value
+
@valuesEqual: (left, right) ->
return true if !left? and !right?
return false if !left?
return false if !right?
return true if left == hqmf.SpecificsManager.any and right == hqmf.SpecificsManager.any
@@ -415,10 +438,15 @@
@buildRowsForMatching: (entryKey, entry, matchesKey, matches) ->
rows = []
for match in matches
occurrences={}
occurrences[entryKey] = entry
- occurrences[matchesKey] = match
+ # from unions and crossproducts we may have a matches key that is a hash of object ids mapped to the specific occurrence key.
+ # this is because we may have multiple different specific occurrences on the right hand side if it came from a group
+ if (_.isObject(matchesKey))
+ occurrences[matchesKey[match.id]] = match
+ else
+ occurrences[matchesKey] = match
rows.push(new Row(entryKey, occurrences))
rows
# build specific for a given entry (there are no temporal references)
@buildForDataCriteria: (entryKey, entries) ->