class Measure
Constants
- DEFAULT_EFFECTIVE_DATE
- MP_START_DATE
- TYPES
- TYPE_MAP
Public Class Methods
Find the measures matching a patient
# File lib/models/measure.rb, line 85 def self.for_patient(record) where user_id: record.user_id, hqmf_set_id: { '$in' => record.measure_ids } end
Public Instance Methods
# File lib/models/measure.rb, line 129 def all_data_criteria as_hqmf_model.all_data_criteria end
Returns the hqmf-parser's ruby implementation of an HQMF
document. Rebuild from population_criteria, data_criteria, and measure_period JSON
# File lib/models/measure.rb, line 102 def as_hqmf_model json = { "id" => self.measure_id, "title" => self.title, "description" => self.description, "population_criteria" => self.population_criteria, "data_criteria" => self.data_criteria, "source_data_criteria" => self.source_data_criteria, "measure_period" => self.measure_period, "attributes" => self.measure_attributes, "populations" => self.populations, "hqmf_id" => self.hqmf_id, "hqmf_set_id" => self.hqmf_set_id, "hqmf_version_number" => self.hqmf_version_number, "cms_id" => self.cms_id } HQMF::Document.from_json(json) end
# File lib/models/measure.rb, line 133 def as_javascript(population_index, check_crosswalk=false) options = { value_sets: value_sets, episode_ids: episode_ids, continuous_variable: continuous_variable, force_sources: force_sources, custom_functions: custom_functions, check_crosswalk: check_crosswalk } HQMF2JS::Generator::Execution.logic(as_hqmf_model, population_index, options) end
# File lib/models/measure.rb, line 233 def calculate_complexity self.complexity = { populations: [], variables: [] } self.population_criteria.each do |name, precondition| complexity = precondition_complexity(precondition) self.complexity[:populations] << { name: name, complexity: complexity } end self.source_data_criteria.each do |reference, criteria| next unless criteria['variable'] name = criteria['description'] complexity = data_criteria_complexity(reference, calculating_variable: true) self.complexity[:variables] << { name: name, complexity: complexity } end self.complexity end
Clear any cached JavaScript, forcing it to be generated next time it's requested
# File lib/models/measure.rb, line 70 def clear_cached_js self.map_fns.map! { nil } self.save end
Return the list of all data criteria keys in this measure, indexed by population code
# File lib/models/measure.rb, line 180 def criteria_keys_by_population criteria_keys_by_population = {} population_criteria.each do |name, precondition| criteria_keys_by_population[name] = precondition_criteria_keys(precondition).reject { |ck| ck == 'MeasurePeriod' } end criteria_keys_by_population end
# File lib/models/measure.rb, line 203 def data_criteria_complexity(criteria_reference, options = {}) options.reverse_merge! calculating_variable: false # We want to calculate the number of branching paths, which we can normally do by counting leaf nodes. # This is more complicated for data criteria because, in addition to direct children, the criteria can # also have temporal references, which can themselves branch. Our approach is to calculate an initial # number of leaf nodes through looking at direct children and then seeing if any additional leaves are # added through temporal references. A temporal reference that doesn't branch doesn't add a leaf node. # Finally, this reference may be a variable, in which case we consider this a leaf node *unless* we are # explicitly calculating the complexity of the variable itself if criteria = self.data_criteria[criteria_reference] complexity = if criteria['children_criteria'].present? && (!criteria['variable'] || options[:calculating_variable]) criteria['children_criteria'].map { |c| data_criteria_complexity(c) }.sum else 1 end complexity + if criteria['temporal_references'].present? criteria['temporal_references'].map { |tr| data_criteria_complexity(tr['reference']) - 1 }.sum else 0 end else 1 end end
Given a data criteria, return the list of all data criteria keys referenced within, either through children criteria or temporal references; this includes the passed in criteria reference
# File lib/models/measure.rb, line 155 def data_criteria_criteria_keys(criteria_reference) criteria_keys = [criteria_reference] if criteria = self.data_criteria[criteria_reference] if criteria['children_criteria'].present? criteria_keys.concat(criteria['children_criteria'].map { |c| data_criteria_criteria_keys(c) }.flatten) end if criteria['temporal_references'].present? criteria_keys.concat(criteria['temporal_references'].map { |tr| data_criteria_criteria_keys(tr['reference']) }.flatten) end end criteria_keys end
Compute a simplified diff hash for Complexity Dashboard usage; stored within measure.latest_diff
# File lib/models/measure.rb, line 267 def diff(other) HQMF::Measure::LogicExtractor.get_measure_logic_diff(self,other,true) end
# File lib/models/measure.rb, line 254 def extract_measure_logic self.measure_logic = [] # There are occasional issues extracting measure logic; while we want to fix them we also don't want logic # extraction issues to hold up loading or updating a measure begin self.measure_logic.concat HQMF::Measure::LogicExtractor.new().population_logic(self) rescue => e self.measure_logic << "Error parsing measure logic: #{e.message}" end self.measure_logic end
Generate and cache all the javascript for the measure, optionally clearing the cache first
# File lib/models/measure.rb, line 65 def generate_js(options = {}) populations.each_with_index { |p, idx| map_fn(idx, options) } end
Cache the generated JS code, with optional options to manipulate cached result
# File lib/models/measure.rb, line 54 def map_fn(population_index, options = {}) options.assert_valid_keys :clear_db_cache, :cache_result_in_db, :check_crosswalk # Defaults are: don't clear the cache, do cache the result in the DB, use user specified crosswalk setting options.reverse_merge! clear_db_cache: false, cache_result_in_db: true, check_crosswalk: !!self.user.try(:crosswalk_enabled) self.map_fns[population_index] = nil if options[:clear_db_cache] self.map_fns[population_index] ||= as_javascript(population_index, options[:check_crosswalk]) save if changed? && options[:cache_result_in_db] self.map_fns[population_index] end
# File lib/models/measure.rb, line 273 def measure_json(population_index=0,check_crosswalk=false) options = { value_sets: value_sets, episode_ids: episode_ids, continuous_variable: continuous_variable, force_sources: force_sources, custom_functions: custom_functions, check_crosswalk: check_crosswalk } population_index ||= 0 json = { id: self.hqmf_id, nqf_id: self.measure_id, hqmf_id: self.hqmf_id, hqmf_set_id: self.hqmf_set_id, hqmf_version_number: self.hqmf_version_number, cms_id: self.cms_id, name: self.title, description: self.description, type: self.type, category: self.category, map_fn: HQMF2JS::Generator::Execution.measure_js(self.as_hqmf_model, population_index, options), continuous_variable: self.continuous_variable, episode_of_care: self.episode_of_care, hqmf_document: self.as_hqmf_model.to_json } if (self.populations.count > 1) sub_ids = ('a'..'az').to_a json[:sub_id] = sub_ids[population_index] population_title = self.populations[population_index]['title'] json[:subtitle] = population_title json[:short_subtitle] = population_title end if self.continuous_variable observation = self.population_criteria[self.populations[population_index][HQMF::PopulationCriteria::OBSERV]] json[:aggregator] = observation['aggregator'] end json[:oids] = self.value_sets.map{|value_set| value_set.oid}.uniq population_ids = {} HQMF::PopulationCriteria::ALL_POPULATION_CODES.each do |type| population_key = self.populations[population_index][type] population_criteria = self.population_criteria[population_key] if (population_criteria) population_ids[type] = population_criteria['hqmf_id'] end end stratification = self['populations'][population_index]['stratification'] if stratification population_ids['stratification'] = stratification end json[:population_ids] = population_ids json end
Measure
Complexity Analysis ##############################
# File lib/models/measure.rb, line 190 def precondition_complexity(precondition) # We want to calculate the number of branching paths; we can do that by simply counting the leaf nodes. # Any children of this particular node can appear either through child preconditions or by reference to a # data criteria. ASSERTION: a precondition can never both have child preconditions and a data criteria. if precondition['preconditions'] && precondition['preconditions'].size > 0 precondition['preconditions'].map { |p| precondition_complexity(p) }.sum elsif precondition['reference'] data_criteria_complexity(precondition['reference']) else 1 end end
Given a precondition, return the list of all data criteria keys referenced within
# File lib/models/measure.rb, line 169 def precondition_criteria_keys(precondition) if precondition['preconditions'] && precondition['preconditions'].size > 0 precondition['preconditions'].map { |p| precondition_criteria_keys(p) }.flatten elsif precondition['reference'] data_criteria_criteria_keys(precondition['reference']) else [] end end
# File lib/models/measure.rb, line 146 def set_continuous_variable self.continuous_variable = populations.map {|x| x.keys}.flatten.uniq.include? HQMF::PopulationCriteria::MSRPOPL true end
# File lib/models/measure.rb, line 122 def value_sets options = { oid: value_set_oids } options[:user_id] = user.id if user? @value_sets ||= HealthDataStandards::SVS::ValueSet.in(options) @value_sets end