UNPKG

node-qme

Version:

Quaility measure calculation engine

111 lines (105 loc) 4.81 kB
"use strict"; /* Base class for measure sources to extend. SubClasses will need to implement the getMeasureDef method to return the measure defintion to be used for generating executable measures. Bundle is a measure source that loades definitions from measure bundles. MongoSource is a measure source that loads the definitions from mongodb */ module.exports = class MeasureSource { constructor(){ this.generated_measures = {}; } /* Retrieve the measure definition for the given measrue id and sub id */ getMeasureDef(measure_id, sub_id){ throw "Implement me"; } /* Retrieve the executable measure. @param @param @returns an instance object that can generate measures for execution. Returned objects have a generate(options) method on them that will generate executable measures based on the options passed in such as effective_date and enable_logging; */ getMeasure(measure_id, sub_id) { //short curcuit if we can var id = this.getMeasureAndSubId(measure_id, sub_id); var cache_id = `${id.id}_${id.sub_id}` if (this.generated_measures[cache_id]) { return this.generated_measures[cache_id]; } else if (!this.getMeasureDef(id.id, id.sub_id)) { return; } // need to scope the context that these are evaluated in to prevent // clobbering other measures , used in eval below let context = {} var measure = this.getMeasureDef(id.id, id.sub_id) var cms_id = measure.sub_id ? `${measure.cms_id}${measure.sub_id}` : measure.cms_id var template = _.template(`"use strict"; class ${cms_id} { constructor(){ this.hqmf_id = "<%= hqmf_id %>"; this.sub_id=<%= (sub_id) ? "'" + sub_id +"'": 'null' %>; this.cms_id=<%= (cms_id) ? "'" + cms_id +"'": 'null' %>; this.continuous_variable = <%= continuous_variable ? 'true' : 'false' %>; this.aggregator = <%= aggregator ? "'" + aggregator + "'" : 'null' %>; this.population_ids = <%= JSON.stringify(population_ids) %>; this.measure = <%= JSON.stringify(measure) %> } generate(options){ var hqmfjs = {}; <%= logic %> return hqmfjs; } }`) let logic_template = _.template(measure.map_fn); let binding = { logic: logic_template({ effective_date: "options.effective_date;", enable_logging: "options.enable_logging;", enable_rationale: "options.enable_rationale;", short_circuit: "options.short_circuit;" }), name: measure_id, hqmf_id: measure.hqmf_id, sub_id: measure.sub_id, continuous_variable: measure.continuous_variable, aggregator: measure.aggregator, population_ids: measure.population_ids, cms_id: measure.cms_id, measure: measure }; var cl = eval.call(context, template(binding)) this.generated_measures[cache_id] = new cl(); return this.generated_measures[cache_id]; } /* Utility method that will analyze the measure id and sub id for different formats. Measure id may be the CMS id in the format CMS#v# , the CMS id may also include the sub_id value CMS#v#sub_id for example CMS182v5a. THe measure_id may also be the HQMF id which could also conditionally contain the sub_id separated by a colon. Measure id may also be a json object {measure_id: "" , sub_id : ""} where measure_id is the CMS or HQMF ids sans sub_id and the sub_id would be the sub_id or null. If the measure_id parameter is a string minus the sub_id then the sub_id parameter will be used otherwise it is ignored. */ getMeasureAndSubId(measure_id, sub_id){ // is measure id a hash? if(measure_id.id){ return measure_id; } // is it a concatinated CMS##v#sub_id format? var res = /CMS\d*v\d*([a-z]*)?/.exec(measure_id); if(res){ var strip = res[1] ? res[1].length : 0 measure_id = measure_id.slice(0,measure_id.length - strip) if(sub_id == null && sub_id != res[1]){ sub_id = res[1] } return {id: measure_id, sub_id: sub_id}; }else{ // is it an HQMF_ID:SUB_ID format var parts = measure_id.split(":") var ret = {} if(parts.length == 2){ return {id: parts[0], sub_id: parts[1]}; }else{ return {id: measure_id, sub_id: sub_id}; } } } }