cqm-models 1.0.3 → 1.1.1.0
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.
- checksums.yaml +5 -5
- data/.eslintrc.json +10 -2
- data/.github/PULL_REQUEST_TEMPLATE.md +0 -4
- data/.rubocop.yml +3 -0
- data/.travis.yml +31 -1
- data/README.md +59 -2
- data/app/assets/javascripts/AdverseEvent.js +16 -7
- data/app/assets/javascripts/AllDataElements.js +6 -6
- data/app/assets/javascripts/AllergyIntolerance.js +16 -7
- data/app/assets/javascripts/AssessmentOrder.js +15 -6
- data/app/assets/javascripts/AssessmentPerformed.js +16 -7
- data/app/assets/javascripts/AssessmentRecommended.js +16 -7
- data/app/assets/javascripts/CareGoal.js +16 -7
- data/app/assets/javascripts/CommunicationPerformed.js +15 -6
- data/app/assets/javascripts/DeviceApplied.js +16 -7
- data/app/assets/javascripts/DeviceOrder.js +16 -7
- data/app/assets/javascripts/DeviceRecommended.js +16 -7
- data/app/assets/javascripts/Diagnosis.js +16 -7
- data/app/assets/javascripts/DiagnosticStudyOrder.js +16 -7
- data/app/assets/javascripts/DiagnosticStudyPerformed.js +16 -7
- data/app/assets/javascripts/DiagnosticStudyRecommended.js +16 -7
- data/app/assets/javascripts/EncounterOrder.js +16 -7
- data/app/assets/javascripts/EncounterPerformed.js +16 -7
- data/app/assets/javascripts/EncounterRecommended.js +16 -7
- data/app/assets/javascripts/FamilyHistory.js +16 -7
- data/app/assets/javascripts/Id.js +7 -3
- data/app/assets/javascripts/ImmunizationAdministered.js +16 -7
- data/app/assets/javascripts/ImmunizationOrder.js +16 -7
- data/app/assets/javascripts/IndividualResult.js +7 -2
- data/app/assets/javascripts/InterventionOrder.js +16 -7
- data/app/assets/javascripts/InterventionPerformed.js +16 -7
- data/app/assets/javascripts/InterventionRecommended.js +16 -7
- data/app/assets/javascripts/LaboratoryTestOrder.js +16 -7
- data/app/assets/javascripts/LaboratoryTestPerformed.js +16 -7
- data/app/assets/javascripts/LaboratoryTestRecommended.js +16 -7
- data/app/assets/javascripts/MedicationActive.js +16 -7
- data/app/assets/javascripts/MedicationAdministered.js +16 -7
- data/app/assets/javascripts/MedicationDischarge.js +16 -7
- data/app/assets/javascripts/MedicationDispensed.js +16 -7
- data/app/assets/javascripts/MedicationOrder.js +16 -7
- data/app/assets/javascripts/Participation.js +15 -6
- data/app/assets/javascripts/PatientCareExperience.js +16 -7
- data/app/assets/javascripts/PatientCharacteristic.js +16 -7
- data/app/assets/javascripts/PatientCharacteristicBirthdate.js +16 -7
- data/app/assets/javascripts/PatientCharacteristicClinicalTrialParticipant.js +16 -7
- data/app/assets/javascripts/PatientCharacteristicEthnicity.js +16 -7
- data/app/assets/javascripts/PatientCharacteristicExpired.js +16 -7
- data/app/assets/javascripts/PatientCharacteristicPayer.js +16 -7
- data/app/assets/javascripts/PatientCharacteristicRace.js +16 -7
- data/app/assets/javascripts/PatientCharacteristicSex.js +16 -7
- data/app/assets/javascripts/PhysicalExamOrder.js +16 -7
- data/app/assets/javascripts/PhysicalExamPerformed.js +16 -7
- data/app/assets/javascripts/PhysicalExamRecommended.js +16 -7
- data/app/assets/javascripts/ProcedureOrder.js +16 -7
- data/app/assets/javascripts/ProcedurePerformed.js +16 -7
- data/app/assets/javascripts/ProcedureRecommended.js +16 -7
- data/app/assets/javascripts/ProviderCareExperience.js +16 -7
- data/app/assets/javascripts/ProviderCharacteristic.js +16 -7
- data/app/assets/javascripts/QDMPatient.js +262 -0
- data/app/assets/javascripts/Result.js +7 -2
- data/app/assets/javascripts/ResultComponent.js +14 -6
- data/app/assets/javascripts/SubstanceAdministered.js +16 -7
- data/app/assets/javascripts/SubstanceOrder.js +16 -7
- data/app/assets/javascripts/SubstanceRecommended.js +16 -7
- data/app/assets/javascripts/Symptom.js +16 -7
- data/app/assets/javascripts/attributes/Component.js +30 -0
- data/app/assets/javascripts/attributes/FacilityLocation.js +30 -0
- data/app/assets/javascripts/basetypes/Any.js +1 -1
- data/app/assets/javascripts/basetypes/Code.js +1 -1
- data/app/assets/javascripts/basetypes/DataElement.js +2 -1
- data/app/assets/javascripts/basetypes/DateTime.js +5 -1
- data/app/assets/javascripts/basetypes/Interval.js +1 -1
- data/app/assets/javascripts/basetypes/Quantity.js +1 -1
- data/app/assets/javascripts/basetypes/Ratio.js +1 -1
- data/app/assets/javascripts/browser.js +3 -0
- data/app/assets/javascripts/cqm/AllCQMModels.js +24 -0
- data/app/assets/javascripts/cqm/CQLLibrary.js +32 -0
- data/app/assets/javascripts/cqm/CQLStatementDependency.js +28 -0
- data/app/assets/javascripts/cqm/Concept.js +17 -0
- data/app/assets/javascripts/cqm/Measure.js +108 -0
- data/app/assets/javascripts/{MeasurePackage.js → cqm/MeasurePackage.js} +9 -3
- data/app/assets/javascripts/cqm/Patient.js +38 -0
- data/app/assets/javascripts/cqm/PopulationSet.js +88 -0
- data/app/assets/javascripts/cqm/Provider.js +44 -0
- data/app/assets/javascripts/cqm/ValueSet.js +26 -0
- data/app/assets/javascripts/index.js +18 -8
- data/app/models/{qdm/tacoma → cqm}/concept.rb +4 -4
- data/app/models/cqm/cql_library.rb +22 -0
- data/app/models/cqm/cql_statement_dependency.rb +24 -0
- data/app/models/cqm/measure.rb +105 -0
- data/app/models/{qdm/tacoma → cqm}/measure_package.rb +2 -2
- data/app/models/cqm/patient.rb +20 -0
- data/app/models/cqm/population_set.rb +86 -0
- data/app/models/cqm/provider.rb +110 -0
- data/app/models/cqm/valueset.rb +15 -0
- data/app/models/hqmfOid_to_datatype_map.json +55 -0
- data/app/models/model_finder.rb +12 -0
- data/app/models/models.rb +18 -6
- data/app/models/qdm/adverse_event.rb +3 -2
- data/app/models/qdm/allergy_intolerance.rb +2 -1
- data/app/models/qdm/assessment_order.rb +1 -0
- data/app/models/qdm/assessment_performed.rb +2 -1
- data/app/models/qdm/assessment_recommended.rb +2 -1
- data/app/models/qdm/attributes/attribute.rb +63 -0
- data/app/models/qdm/{component.rb → attributes/component.rb} +1 -1
- data/app/models/qdm/{facility_location.rb → attributes/facility_location.rb} +1 -1
- data/app/models/qdm/basetypes/data_element.rb +21 -6
- data/app/models/qdm/basetypes/interval.rb +2 -1
- data/app/models/qdm/care_goal.rb +2 -1
- data/app/models/qdm/communication_performed.rb +1 -0
- data/app/models/qdm/device_applied.rb +2 -1
- data/app/models/qdm/device_order.rb +2 -1
- data/app/models/qdm/device_recommended.rb +2 -1
- data/app/models/qdm/diagnosis.rb +2 -1
- data/app/models/qdm/diagnostic_study_order.rb +2 -1
- data/app/models/qdm/diagnostic_study_performed.rb +3 -2
- data/app/models/qdm/diagnostic_study_recommended.rb +2 -1
- data/app/models/qdm/encounter_order.rb +3 -2
- data/app/models/qdm/encounter_performed.rb +2 -1
- data/app/models/qdm/encounter_recommended.rb +3 -2
- data/app/models/qdm/family_history.rb +2 -1
- data/app/models/qdm/immunization_administered.rb +2 -1
- data/app/models/qdm/immunization_order.rb +2 -1
- data/app/models/qdm/intervention_order.rb +2 -1
- data/app/models/qdm/intervention_performed.rb +2 -1
- data/app/models/qdm/intervention_recommended.rb +2 -1
- data/app/models/qdm/laboratory_test_order.rb +2 -1
- data/app/models/qdm/laboratory_test_performed.rb +2 -1
- data/app/models/qdm/laboratory_test_recommended.rb +2 -1
- data/app/models/qdm/medication_active.rb +2 -1
- data/app/models/qdm/medication_administered.rb +2 -1
- data/app/models/qdm/medication_discharge.rb +2 -1
- data/app/models/qdm/medication_dispensed.rb +4 -3
- data/app/models/qdm/medication_order.rb +3 -2
- data/app/models/qdm/participation.rb +1 -0
- data/app/models/qdm/patient.rb +7 -4
- data/app/models/qdm/patient_care_experience.rb +2 -1
- data/app/models/qdm/patient_characteristic.rb +2 -1
- data/app/models/qdm/patient_characteristic_birthdate.rb +2 -1
- data/app/models/qdm/patient_characteristic_clinical_trial_participant.rb +2 -1
- data/app/models/qdm/patient_characteristic_ethnicity.rb +2 -1
- data/app/models/qdm/patient_characteristic_expired.rb +2 -1
- data/app/models/qdm/patient_characteristic_payer.rb +2 -1
- data/app/models/qdm/patient_characteristic_race.rb +2 -1
- data/app/models/qdm/patient_characteristic_sex.rb +2 -1
- data/app/models/qdm/physical_exam_order.rb +2 -1
- data/app/models/qdm/physical_exam_performed.rb +2 -1
- data/app/models/qdm/physical_exam_recommended.rb +2 -1
- data/app/models/qdm/procedure_order.rb +2 -1
- data/app/models/qdm/procedure_performed.rb +2 -1
- data/app/models/qdm/procedure_recommended.rb +2 -1
- data/app/models/qdm/provider_care_experience.rb +2 -1
- data/app/models/qdm/provider_characteristic.rb +2 -1
- data/app/models/qdm/substance_administered.rb +2 -1
- data/app/models/qdm/substance_order.rb +2 -1
- data/app/models/qdm/substance_recommended.rb +2 -1
- data/app/models/qdm/symptom.rb +2 -1
- data/bin/build_cql_execution.sh +8 -0
- data/bin/validate_browser.sh +17 -0
- data/bin/validate_generator.sh +12 -0
- data/cqm-models.gemspec +5 -2
- data/data/oids_qdm_5.4.json +321 -0
- data/data/{oids.json → oids_unversioned.json} +0 -0
- data/dist/browser.js +102937 -0
- data/dist/index.js +36637 -36540
- data/lib/generate_models.rb +89 -93
- data/lib/generate_patients.rb +125 -0
- data/lib/generate_types.rb +64 -0
- data/lib/generators/custom_mongo/model.rb.tt +20 -0
- data/lib/generators/custom_mongo/model_generator.rb +34 -0
- data/notice.md +9 -0
- data/package.json +12 -6
- data/templates/id_template.js.erb +8 -3
- data/templates/index_template.js.erb +18 -8
- data/templates/models_template.rb.erb +20 -4
- data/templates/mongoose_template.js.erb +23 -15
- data/templates/patient_extension.rb.erb +7 -4
- data/templates/patient_template.js.erb +88 -87
- data/yarn.lock +552 -347
- metadata +86 -19
- data/app/assets/javascripts/Component.js +0 -26
- data/app/assets/javascripts/Concept.js +0 -14
- data/app/assets/javascripts/FacilityLocation.js +0 -26
- data/app/assets/javascripts/Measure.js +0 -78
- data/app/assets/javascripts/Patient.js +0 -262
- data/app/assets/javascripts/ValueSet.js +0 -30
- data/app/models/qdm/tacoma/measure.rb +0 -174
- data/app/models/qdm/tacoma/valueset.rb +0 -68
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const mongoose = require('mongoose/browser');
|
|
2
|
+
const Id = require('../Id');
|
|
3
|
+
|
|
4
|
+
const [Schema, String, Boolean] = [
|
|
5
|
+
mongoose.Schema,
|
|
6
|
+
mongoose.Schema.Types.String,
|
|
7
|
+
mongoose.Schema.Types.Boolean,
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
const AddressSchema = new mongoose.Schema({
|
|
11
|
+
street: [String],
|
|
12
|
+
city: String,
|
|
13
|
+
state: String,
|
|
14
|
+
zip: String,
|
|
15
|
+
country: String,
|
|
16
|
+
use: String,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const TelecomSchema = new mongoose.Schema({
|
|
20
|
+
use: String,
|
|
21
|
+
value: String,
|
|
22
|
+
preferred: Boolean,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const ProviderSchema = new Schema({
|
|
26
|
+
_type: { type: String, default: 'Provider' },
|
|
27
|
+
|
|
28
|
+
givenNames: [String],
|
|
29
|
+
familyName: String,
|
|
30
|
+
specialty: String,
|
|
31
|
+
title: String,
|
|
32
|
+
addresses: [AddressSchema],
|
|
33
|
+
telecoms: [TelecomSchema],
|
|
34
|
+
ids: [Id.IdSchema],
|
|
35
|
+
|
|
36
|
+
}, { id: false });
|
|
37
|
+
|
|
38
|
+
module.exports.ProviderSchema = ProviderSchema;
|
|
39
|
+
class Provider extends mongoose.Document {
|
|
40
|
+
constructor(object) {
|
|
41
|
+
super(object, ProviderSchema);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
module.exports.Provider = Provider;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const mongoose = require('mongoose/browser');
|
|
2
|
+
const Concept = require('./Concept.js');
|
|
3
|
+
|
|
4
|
+
const [String] = [mongoose.Schema.Types.String];
|
|
5
|
+
|
|
6
|
+
const ValueSetSchema = new mongoose.Schema(
|
|
7
|
+
{
|
|
8
|
+
oid: String,
|
|
9
|
+
display_name: String,
|
|
10
|
+
version: String,
|
|
11
|
+
|
|
12
|
+
concepts: [Concept.ConceptSchema],
|
|
13
|
+
},
|
|
14
|
+
// Options
|
|
15
|
+
{
|
|
16
|
+
timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' },
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
module.exports.ValueSetSchema = ValueSetSchema;
|
|
21
|
+
class ValueSet extends mongoose.Document {
|
|
22
|
+
constructor(object) {
|
|
23
|
+
super(object, ValueSetSchema);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
module.exports.ValueSet = ValueSet;
|
|
@@ -2,13 +2,23 @@ module.exports = require('./AllDataElements.js');
|
|
|
2
2
|
module.exports.CQL = require('cql-execution');
|
|
3
3
|
module.exports.Result = require('./Result.js').Result;
|
|
4
4
|
module.exports.ResultSchema = require('./Result.js').ResultSchema;
|
|
5
|
-
module.exports.Measure = require('./Measure.js').Measure;
|
|
6
|
-
module.exports.MeasureSchema = require('./Measure.js').MeasureSchema;
|
|
7
|
-
module.exports.MeasurePackage = require('./MeasurePackage.js').MeasurePackage;
|
|
8
|
-
module.exports.MeasurePackageSchema = require('./MeasurePackage.js').MeasurePackageSchema;
|
|
9
|
-
module.exports.
|
|
10
|
-
module.exports.
|
|
11
|
-
module.exports.
|
|
12
|
-
module.exports.
|
|
5
|
+
module.exports.Measure = require('./cqm/Measure.js').Measure;
|
|
6
|
+
module.exports.MeasureSchema = require('./cqm/Measure.js').MeasureSchema;
|
|
7
|
+
module.exports.MeasurePackage = require('./cqm/MeasurePackage.js').MeasurePackage;
|
|
8
|
+
module.exports.MeasurePackageSchema = require('./cqm/MeasurePackage.js').MeasurePackageSchema;
|
|
9
|
+
module.exports.Patient = require('./cqm/Patient.js').Patient;
|
|
10
|
+
module.exports.PatientSchema = require('./cqm/Patient.js').PatientSchema;
|
|
11
|
+
module.exports.Provider = require('./cqm/Provider.js').Provider;
|
|
12
|
+
module.exports.ProviderSchema = require('./cqm/Provider.js').ProviderSchema;
|
|
13
|
+
module.exports.StatementDependency = require('./cqm/CQLStatementDependency.js').StatementDependency;
|
|
14
|
+
module.exports.StatementDependencySchema = require('./cqm/CQLStatementDependency.js').StatementDependencySchema;
|
|
15
|
+
module.exports.PopulationSet = require('./cqm/PopulationSet.js').PopulationSet;
|
|
16
|
+
module.exports.PopulationSetSchema = require('./cqm/PopulationSet.js').PopulationSetSchema;
|
|
17
|
+
module.exports.CQLLibrary = require('./cqm/CQLLibrary.js').CQLLibrary;
|
|
18
|
+
module.exports.CQLLibrarySchema = require('./cqm/CQLLibrary.js').CQLLibrarySchema;
|
|
19
|
+
module.exports.ValueSet = require('./cqm/ValueSet.js').ValueSet;
|
|
20
|
+
module.exports.ValueSetSchema = require('./cqm/ValueSet.js').ValueSetSchema;
|
|
21
|
+
module.exports.Concept = require('./cqm/Concept.js').Concept;
|
|
22
|
+
module.exports.ConceptSchema = require('./cqm/Concept.js').ConceptSchema;
|
|
13
23
|
module.exports.IndividualResult = require('./IndividualResult').IndividualResult;
|
|
14
24
|
module.exports.IndividualResultSchema = require('./IndividualResult').IndividualResultSchema;
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
module
|
|
1
|
+
module CQM
|
|
2
2
|
# Concept is an individual code within a ValueSet, including all of the associated metadata
|
|
3
3
|
# such as code system, version, and display name
|
|
4
4
|
class Concept
|
|
5
5
|
include Mongoid::Document
|
|
6
6
|
field :code, type: String
|
|
7
|
+
field :code_system_oid, type: String
|
|
7
8
|
field :code_system_name, type: String
|
|
8
9
|
field :code_system_version, type: String
|
|
9
10
|
field :display_name, type: String
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
scope :by_code_system, ->(cs) { where(code_system: cs) }
|
|
11
|
+
|
|
12
|
+
embedded_in :value_set
|
|
13
13
|
end
|
|
14
14
|
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module CQM
|
|
2
|
+
# CQLLibrary encapsulates what used to be a Hash in Ruby, by explicitly specifying
|
|
3
|
+
# a library ID, and the CQL string for that library
|
|
4
|
+
class CQLLibrary
|
|
5
|
+
include Mongoid::Document
|
|
6
|
+
embedded_in :measure
|
|
7
|
+
|
|
8
|
+
field :library_name, type: String
|
|
9
|
+
field :library_version, type: String
|
|
10
|
+
field :cql, type: String
|
|
11
|
+
field :elm, type: Hash
|
|
12
|
+
field :elm_annotations, type: Hash
|
|
13
|
+
field :is_main_library, type: Boolean, default: false
|
|
14
|
+
|
|
15
|
+
# Currently this is only relevant for cql libraries that are included in composite measures,
|
|
16
|
+
# true indicates the library files are in the "top level" folder of the measure package, rather
|
|
17
|
+
# than coming from a component measure folder.
|
|
18
|
+
field :is_top_level, type: Boolean, default: true
|
|
19
|
+
|
|
20
|
+
embeds_many :statement_dependencies, class_name: 'CQM::StatementDependency'
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module CQM
|
|
2
|
+
# Statement is a given CQL Statement within a CQL Library, which has many dependencies
|
|
3
|
+
class StatementDependency
|
|
4
|
+
include Mongoid::Document
|
|
5
|
+
embedded_in :cql_library
|
|
6
|
+
|
|
7
|
+
field :statement_name, type: String
|
|
8
|
+
embeds_many :statement_references
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# StatementReference notes a CQL Library/Statement which a given Statement (in which it is embedded) relies upon. This
|
|
12
|
+
# is also used for populations/stratifications/SDEs to reference their defining statement.
|
|
13
|
+
class StatementReference
|
|
14
|
+
include Mongoid::Document
|
|
15
|
+
embedded_in :statement_dependency
|
|
16
|
+
embedded_in :population_set
|
|
17
|
+
embedded_in :population_map
|
|
18
|
+
embedded_in :stratification
|
|
19
|
+
|
|
20
|
+
field :library_name, type: String
|
|
21
|
+
field :statement_name, type: String
|
|
22
|
+
field :hqmf_id, type: String
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
module CQM
|
|
2
|
+
# Measure contains the information necessary to represent the CQL version of a Clinical Quality Measure,
|
|
3
|
+
# As needed by the Bonnie & Cypress applications
|
|
4
|
+
class Measure
|
|
5
|
+
include Mongoid::Document
|
|
6
|
+
include Mongoid::Timestamps
|
|
7
|
+
|
|
8
|
+
# These are the Mongoid equivalent of the Mongoose "enum" attribute for the respective fields.
|
|
9
|
+
# They throw an error if you try to assign a value that's not in the array.
|
|
10
|
+
validates_inclusion_of :measure_scoring, in: %w[PROPORTION RATIO CONTINUOUS_VARIABLE COHORT]
|
|
11
|
+
validates_inclusion_of :calculation_method, in: %w[PATIENT EPISODE_OF_CARE]
|
|
12
|
+
|
|
13
|
+
IPP = 'IPP'.freeze
|
|
14
|
+
DENOM = 'DENOM'.freeze
|
|
15
|
+
NUMER = 'NUMER'.freeze
|
|
16
|
+
NUMEX = 'NUMEX'.freeze
|
|
17
|
+
DENEXCEP = 'DENEXCEP'.freeze
|
|
18
|
+
DENEX = 'DENEX'.freeze
|
|
19
|
+
MSRPOPL = 'MSRPOPL'.freeze
|
|
20
|
+
OBSERV = 'OBSERV'.freeze
|
|
21
|
+
MSRPOPLEX = 'MSRPOPLEX'.freeze
|
|
22
|
+
|
|
23
|
+
STRAT = 'STRAT'.freeze
|
|
24
|
+
|
|
25
|
+
ALL_POPULATION_CODES = [STRAT, IPP, DENOM, DENEX, NUMER, NUMEX, DENEXCEP, MSRPOPL, OBSERV, MSRPOPLEX].freeze
|
|
26
|
+
|
|
27
|
+
CQL_SKIP_STATEMENTS = ['SDE Ethnicity', 'SDE Payer', 'SDE Race', 'SDE Sex'].freeze
|
|
28
|
+
|
|
29
|
+
# A version-specific UUID for the measure
|
|
30
|
+
field :hqmf_id, type: String
|
|
31
|
+
# A version-neutral UUID for the measure
|
|
32
|
+
field :hqmf_set_id, type: String
|
|
33
|
+
# A Semantic Version-compliant string (e.g. "2.3.4") for the measure
|
|
34
|
+
field :hqmf_version_number, type: String
|
|
35
|
+
# A CMS-style string (e.g. "CMS2v4") for the measure
|
|
36
|
+
field :cms_id, type: String
|
|
37
|
+
field :title, type: String, default: ''
|
|
38
|
+
field :description, type: String, default: ''
|
|
39
|
+
|
|
40
|
+
# Composite/component measure fields
|
|
41
|
+
field :composite, type: Boolean, default: false
|
|
42
|
+
field :component, type: Boolean, default: false
|
|
43
|
+
field :component_hqmf_set_ids, type: Array, default: []
|
|
44
|
+
field :composite_hqmf_set_id, type: String
|
|
45
|
+
|
|
46
|
+
# Measure type variables
|
|
47
|
+
# Note: these are constrained to an enumeration of value options above, via validates_inclusion_of
|
|
48
|
+
field :measure_scoring, type: String, default: 'PROPORTION'
|
|
49
|
+
field :calculation_method, type: String, default: 'PATIENT'
|
|
50
|
+
field :calculate_sdes, type: Boolean
|
|
51
|
+
|
|
52
|
+
# ELM/CQL Measure-logic related data
|
|
53
|
+
# Field name changed from 'cql' to 'cql_libraries' because the semantics of
|
|
54
|
+
# embeds_many :cqls sounded weird
|
|
55
|
+
embeds_many :cql_libraries, class_name: 'CQM::CQLLibrary'
|
|
56
|
+
field :main_cql_library, type: String
|
|
57
|
+
|
|
58
|
+
# HQMF/Tacoma-specific Measure-logic related data
|
|
59
|
+
field :population_criteria, type: Hash
|
|
60
|
+
field :measure_period, type: Hash
|
|
61
|
+
field :measure_attributes, type: Array
|
|
62
|
+
embeds_many :source_data_criteria, class_name: 'QDM::DataElement'
|
|
63
|
+
|
|
64
|
+
embeds_many :population_sets
|
|
65
|
+
|
|
66
|
+
# Relations to other model classes
|
|
67
|
+
# Note: bundle is removed, Cypress may create their own bundle object and inject the relationship
|
|
68
|
+
has_one :package, class_name: 'CQM::MeasurePackage', inverse_of: :measure, dependent: :destroy # Bonnie-specific
|
|
69
|
+
|
|
70
|
+
# Store this references as an Array on the Measure object,
|
|
71
|
+
# but don't care about the inverse relationship (e.g. we never really care
|
|
72
|
+
# about getting all the measures from a ValueSet object,
|
|
73
|
+
# hence the 'inverse_of: nil')
|
|
74
|
+
has_and_belongs_to_many :value_sets, inverse_of: nil
|
|
75
|
+
|
|
76
|
+
def all_stratifications
|
|
77
|
+
population_sets.flat_map(&:stratifications)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Returns the hqmf-parser's ruby implementation of an HQMF document.
|
|
81
|
+
# Rebuild from population_criteria, data_criteria, and measure_period JSON
|
|
82
|
+
def as_hqmf_model
|
|
83
|
+
json = {
|
|
84
|
+
'id' => hqmf_id,
|
|
85
|
+
'title' => title,
|
|
86
|
+
'description' => description,
|
|
87
|
+
'population_criteria' => population_criteria,
|
|
88
|
+
'data_criteria' => data_criteria,
|
|
89
|
+
'source_data_criteria' => source_data_criteria,
|
|
90
|
+
'measure_period' => measure_period,
|
|
91
|
+
'attributes' => measure_attributes,
|
|
92
|
+
'populations' => populations,
|
|
93
|
+
'hqmf_id' => hqmf_id,
|
|
94
|
+
'hqmf_set_id' => hqmf_set_id,
|
|
95
|
+
'hqmf_version_number' => hqmf_version_number,
|
|
96
|
+
'cms_id' => cms_id
|
|
97
|
+
}
|
|
98
|
+
HQMF::Document.from_json(json)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def all_data_criteria
|
|
102
|
+
as_hqmf_model.all_data_criteria
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
module
|
|
1
|
+
module CQM
|
|
2
2
|
# MeasurePackage stores the uploaded file for a given Measure, so it can be recreated if need be
|
|
3
3
|
class MeasurePackage
|
|
4
4
|
include Mongoid::Document
|
|
5
5
|
include Mongoid::Timestamps
|
|
6
6
|
|
|
7
7
|
field :file, type: BSON::Binary
|
|
8
|
-
belongs_to :measure, class_name: 'Measure', inverse_of: :package
|
|
8
|
+
belongs_to :measure, class_name: 'CQM::Measure', inverse_of: :package
|
|
9
9
|
end
|
|
10
10
|
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module CQM
|
|
2
|
+
# Patient model that holds non-QDM data for the patient
|
|
3
|
+
class Patient
|
|
4
|
+
include Mongoid::Document
|
|
5
|
+
field :givenNames, type: Array
|
|
6
|
+
field :familyName, type: String
|
|
7
|
+
field :bundleId, type: String
|
|
8
|
+
field :expectedValues, type: Array
|
|
9
|
+
field :notes, type: String
|
|
10
|
+
field :measure_ids, type: Array
|
|
11
|
+
|
|
12
|
+
has_and_belongs_to_many :providers, class_name: 'CQM::Provider'
|
|
13
|
+
embeds_one :qdmPatient, class_name: 'QDM::Patient', autobuild: true
|
|
14
|
+
|
|
15
|
+
# Include '_type' in any JSON output. This is necessary for deserialization.
|
|
16
|
+
def to_json(options = nil)
|
|
17
|
+
serializable_hash(include: :_type, methods: :_type).to_json(options)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
module CQM
|
|
2
|
+
# Representation of a population set (aka. PopulationCriteria)
|
|
3
|
+
class PopulationSet
|
|
4
|
+
include Mongoid::Document
|
|
5
|
+
|
|
6
|
+
embedded_in :measure
|
|
7
|
+
|
|
8
|
+
embeds_one :populations, class_name: 'CQM::PopulationMap'
|
|
9
|
+
embeds_many :stratifications
|
|
10
|
+
embeds_many :supplemental_data_elements, class_name: 'CQM::StatementReference'
|
|
11
|
+
embeds_many :observations
|
|
12
|
+
|
|
13
|
+
field :title, type: String
|
|
14
|
+
field :population_set_id, type: String
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Stratification info
|
|
18
|
+
class Stratification
|
|
19
|
+
include Mongoid::Document
|
|
20
|
+
|
|
21
|
+
embedded_in :population_set
|
|
22
|
+
|
|
23
|
+
field :title, type: String
|
|
24
|
+
field :stratification_id, type: String
|
|
25
|
+
field :hqmf_id, type: String
|
|
26
|
+
embeds_one :statement, class_name: 'CQM::StatementReference'
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Observation info
|
|
30
|
+
class Observation
|
|
31
|
+
include Mongoid::Document
|
|
32
|
+
|
|
33
|
+
embedded_in :population_set
|
|
34
|
+
|
|
35
|
+
embeds_one :observation_function, class_name: 'CQM::StatementReference'
|
|
36
|
+
embeds_one :observation_parameter, class_name: 'CQM::StatementReference'
|
|
37
|
+
field :aggregation_type, type: String
|
|
38
|
+
field :hqmf_id, type: String
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Base class for the population maps
|
|
42
|
+
class PopulationMap
|
|
43
|
+
include Mongoid::Document
|
|
44
|
+
|
|
45
|
+
embedded_in :population_set
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# The population map for a porportion population set
|
|
49
|
+
class ProportionPopulationMap < PopulationMap
|
|
50
|
+
include Mongoid::Document
|
|
51
|
+
|
|
52
|
+
embeds_one :IPP, class_name: 'CQM::StatementReference'
|
|
53
|
+
embeds_one :DENOM, class_name: 'CQM::StatementReference'
|
|
54
|
+
embeds_one :NUMER, class_name: 'CQM::StatementReference'
|
|
55
|
+
embeds_one :NUMEX, class_name: 'CQM::StatementReference'
|
|
56
|
+
embeds_one :DENEX, class_name: 'CQM::StatementReference'
|
|
57
|
+
embeds_one :DENEXCEP, class_name: 'CQM::StatementReference'
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# The population map for a ratio population set
|
|
61
|
+
class RatioPopulationMap < PopulationMap
|
|
62
|
+
include Mongoid::Document
|
|
63
|
+
|
|
64
|
+
embeds_one :IPP, class_name: 'CQM::StatementReference'
|
|
65
|
+
embeds_one :DENOM, class_name: 'CQM::StatementReference'
|
|
66
|
+
embeds_one :NUMER, class_name: 'CQM::StatementReference'
|
|
67
|
+
embeds_one :NUMEX, class_name: 'CQM::StatementReference'
|
|
68
|
+
embeds_one :DENEX, class_name: 'CQM::StatementReference'
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# The population map for a continuous variable population set
|
|
72
|
+
class ContinuousVariablePopulationMap < PopulationMap
|
|
73
|
+
include Mongoid::Document
|
|
74
|
+
|
|
75
|
+
embeds_one :IPP, class_name: 'CQM::StatementReference'
|
|
76
|
+
embeds_one :MSRPOPL, class_name: 'CQM::StatementReference'
|
|
77
|
+
embeds_one :MSRPOPLEX, class_name: 'CQM::StatementReference'
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# The population map for a cohort population set
|
|
81
|
+
class CohortPopulationMap < PopulationMap
|
|
82
|
+
include Mongoid::Document
|
|
83
|
+
|
|
84
|
+
embeds_one :IPP, class_name: 'CQM::StatementReference'
|
|
85
|
+
end
|
|
86
|
+
end
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
module CQM
|
|
2
|
+
# Provider model that holds non-QDM data for the provider. As well as indentifiers referenced in QDM
|
|
3
|
+
class Provider
|
|
4
|
+
include Mongoid::Document
|
|
5
|
+
|
|
6
|
+
NPI_OID = '2.16.840.1.113883.4.6'.freeze
|
|
7
|
+
TAX_ID_OID = '2.16.840.1.113883.4.2'.freeze
|
|
8
|
+
CCN_OID = '2.16.840.1.113883.4.336'.freeze
|
|
9
|
+
|
|
10
|
+
field :givenNames, type: Array
|
|
11
|
+
field :familyName, type: String
|
|
12
|
+
field :specialty, type: String
|
|
13
|
+
field :title, type: String
|
|
14
|
+
|
|
15
|
+
validates_uniqueness_of :npi, allow_blank: true
|
|
16
|
+
|
|
17
|
+
embeds_many :addresses
|
|
18
|
+
embeds_many :telecoms
|
|
19
|
+
embeds_many :ids, class_name: 'QDM::Id'
|
|
20
|
+
|
|
21
|
+
def npi=(an_npi)
|
|
22
|
+
cda_id_npi = ids.where(namingSystem: NPI_OID).first
|
|
23
|
+
if cda_id_npi
|
|
24
|
+
cda_id_npi.value = an_npi
|
|
25
|
+
cda_id_npi.save!
|
|
26
|
+
else
|
|
27
|
+
ids << QDM::Id.new(namingSystem: NPI_OID, value: an_npi)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def npi
|
|
32
|
+
cda_id_npi = ids.where(namingSystem: NPI_OID).first
|
|
33
|
+
cda_id_npi ? cda_id_npi.value : nil
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def tin=(a_tin)
|
|
37
|
+
ids << QDM::Id.new(namingSystem: TAX_ID_OID, value: a_tin)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def tin
|
|
41
|
+
cda_id_tin = ids.where(namingSystem: TAX_ID_OID).first
|
|
42
|
+
cda_id_tin ? cda_id_tin.value : nil
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def ccn=(a_ccn)
|
|
46
|
+
cda_id_ccn = ids.where(namingSystem: CCN_OID).first
|
|
47
|
+
if cda_id_ccn
|
|
48
|
+
cda_id_ccn.value = a_ccn
|
|
49
|
+
cda_id_ccn.save!
|
|
50
|
+
else
|
|
51
|
+
ids << QDM::Id.new(namingSystem: CCN_OID, value: a_ccn)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def ccn
|
|
56
|
+
cda_id_ccn = ids.where(namingSystem: CCN_OID).first
|
|
57
|
+
cda_id_ccn ? cda_id_ccn.value : nil
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# validate the NPI, should be 10 or 15 digits total with the final digit being a
|
|
61
|
+
# checksum using the Luhn algorithm with additional special handling as described in
|
|
62
|
+
# https://www.cms.gov/NationalProvIdentStand/Downloads/NPIcheckdigit.pdf
|
|
63
|
+
def self.valid_npi?(npi)
|
|
64
|
+
return false unless npi
|
|
65
|
+
return false if npi.length != 10 && npi.length != 15
|
|
66
|
+
return false if npi.gsub(/\d/, '').length.positive? # npi must be all digits
|
|
67
|
+
return false if npi.length == 15 && (npi =~ /^80840/).nil? # 15 digit npi must start with 80840
|
|
68
|
+
|
|
69
|
+
# checksum is always calculated as if 80840 prefix is present
|
|
70
|
+
npi = '80840' + npi if npi.length == 10
|
|
71
|
+
|
|
72
|
+
luhn_checksum(npi[0, 14]) == npi[14]
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def self.luhn_checksum(num)
|
|
76
|
+
double = { '0' => 0, '1' => 2, '2' => 4, '3' => 6, '4' => 8, '5' => 1, '6' => 3, '7' => 5, '8' => 7, '9' => 9 }
|
|
77
|
+
sum = 0
|
|
78
|
+
num.reverse!
|
|
79
|
+
num.split('').each_with_index do |char, i|
|
|
80
|
+
sum += if (i % 2).zero?
|
|
81
|
+
double[char]
|
|
82
|
+
else
|
|
83
|
+
char.to_i
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
sum = (9 * sum) % 10
|
|
87
|
+
|
|
88
|
+
sum.to_s
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Model for a standard postal address
|
|
93
|
+
class Address
|
|
94
|
+
include Mongoid::Document
|
|
95
|
+
field :street, type: Array, default: []
|
|
96
|
+
field :city, type: String
|
|
97
|
+
field :state, type: String
|
|
98
|
+
field :zip, type: String
|
|
99
|
+
field :country, type: String
|
|
100
|
+
field :use, type: String
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Model for a standard telephone number
|
|
104
|
+
class Telecom
|
|
105
|
+
include Mongoid::Document
|
|
106
|
+
field :use, type: String
|
|
107
|
+
field :value, type: String
|
|
108
|
+
field :preferred, type: Boolean
|
|
109
|
+
end
|
|
110
|
+
end
|