cqm-models 0.7.7 → 0.8.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 +4 -4
- data/.rubocop.yml +3 -0
- data/README.md +1 -0
- data/app/assets/javascripts/IndividualResult.js +54 -0
- data/app/assets/javascripts/Measure.js +18 -18
- data/app/assets/javascripts/Patient.js +2 -1
- data/app/assets/javascripts/ValueSet.js +4 -4
- data/app/assets/javascripts/index.js +2 -0
- data/app/models/models.rb +1 -0
- data/app/models/qdm/basetypes/data_element.rb +17 -0
- data/app/models/qdm/basetypes/interval.rb +23 -0
- data/app/models/qdm/patient.rb +11 -0
- data/app/models/qdm/tacoma/individual_result.rb +39 -0
- data/app/models/qdm/tacoma/measure.rb +1 -1
- data/cqm-models.gemspec +1 -1
- data/dist/index.js +1177 -787
- data/package.json +2 -2
- data/templates/index_template.js.erb +2 -0
- data/yarn.lock +5 -5
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: adce07d4828edeec55d0a07a98a55f7cd4ca0e6f
|
4
|
+
data.tar.gz: fd48e3958c11556440fa984040a426437fb65823
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 34e5edecfca3aebe628265178824100649c0abadce2b6c730acf7ed368f1d6c958606d12e31fa9a1e9a8c1bc0a80bd3a46daa68ab52123604eafea31e8f81010
|
7
|
+
data.tar.gz: 219d45b6e063aaa360eb8800b6f84fe496fb70625589f5417f0203dc1ad98a64d9253fe1d7592a41502b646ef08e6040dc3de410fa961aba42ba60cdd62f641b
|
data/.rubocop.yml
CHANGED
@@ -37,6 +37,9 @@ Naming/UncommunicativeMethodParamName:
|
|
37
37
|
Naming/VariableName:
|
38
38
|
Enabled: false
|
39
39
|
|
40
|
+
Style/DateTime:
|
41
|
+
Enabled: false
|
42
|
+
|
40
43
|
# Only disabled until the cyclomatic complexity method in measure.rb (ported from bonnie-bundler) is rewritten
|
41
44
|
Lint/NestedMethodDefinition:
|
42
45
|
Enabled: false
|
data/README.md
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
[](https://travis-ci.org/projecttacoma/cqm-models)
|
2
2
|
[](https://badge.fury.io/rb/cqm-models)
|
3
|
+

|
3
4
|
|
4
5
|
# cqm-models
|
5
6
|
|
@@ -0,0 +1,54 @@
|
|
1
|
+
const mongoose = require('mongoose');
|
2
|
+
|
3
|
+
const [Number, String, Mixed, ObjectId] = [
|
4
|
+
mongoose.Schema.Types.Number,
|
5
|
+
mongoose.Schema.Types.String,
|
6
|
+
mongoose.Schema.Types.Mixed,
|
7
|
+
mongoose.Schema.Types.ObjectId,
|
8
|
+
];
|
9
|
+
|
10
|
+
const IndividualResultSchema = mongoose.Schema(
|
11
|
+
{
|
12
|
+
// Population Attributes
|
13
|
+
STRAT: Number,
|
14
|
+
IPP: Number,
|
15
|
+
DENOM: Number,
|
16
|
+
NUMER: Number,
|
17
|
+
NUMEX: Number,
|
18
|
+
DENEX: Number,
|
19
|
+
DENEXCEP: Number,
|
20
|
+
MSRPOPL: Number,
|
21
|
+
OBSERV: Number,
|
22
|
+
MSRPOPLEX: Number,
|
23
|
+
|
24
|
+
// Result Attributes
|
25
|
+
clause_results: Mixed,
|
26
|
+
episode_results: Mixed,
|
27
|
+
statement_results: Mixed,
|
28
|
+
|
29
|
+
// This field is for application specific information only. If both Bonnie and
|
30
|
+
// Cypress use a common field, it should be made a field on this model,
|
31
|
+
// and not put into extendedData.
|
32
|
+
extendedData: {},
|
33
|
+
|
34
|
+
// Calculation State attributes
|
35
|
+
state: {
|
36
|
+
type: String,
|
37
|
+
enum: ['queued', 'running', 'complete', 'cancelled', 'failed'],
|
38
|
+
default: 'queued',
|
39
|
+
},
|
40
|
+
|
41
|
+
// Relations to other model classes
|
42
|
+
// 'alias' field makes it so you can call obj.measure, and get the object referenced by measure_id
|
43
|
+
measure_id: { type: ObjectId, ref: 'Measure', alias: 'measure' },
|
44
|
+
patient_id: { type: ObjectId, ref: 'Patient', alias: 'patient' },
|
45
|
+
|
46
|
+
},
|
47
|
+
// Options
|
48
|
+
{
|
49
|
+
timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' }, // These are the Mongoid conventions for timestamps
|
50
|
+
}
|
51
|
+
);
|
52
|
+
|
53
|
+
module.exports.IndividualResultSchema = IndividualResultSchema;
|
54
|
+
module.exports.IndividualResult = mongoose.model('individual_result', IndividualResultSchema);
|
@@ -3,7 +3,7 @@ const Code = require('./basetypes/Code');
|
|
3
3
|
const Interval = require('./basetypes/Interval');
|
4
4
|
const Quantity = require('./basetypes/Quantity');
|
5
5
|
|
6
|
-
const [
|
6
|
+
const [Number, String, Boolean, Mixed, ObjectId, Date] = [
|
7
7
|
mongoose.Schema.Types.Number,
|
8
8
|
mongoose.Schema.Types.String,
|
9
9
|
mongoose.Schema.Types.Boolean,
|
@@ -15,32 +15,32 @@ const [mNumber, mString, mBoolean, Mixed, ObjectId, mDate] = [
|
|
15
15
|
const MeasureSchema = mongoose.Schema(
|
16
16
|
{
|
17
17
|
// ID/other measure information
|
18
|
-
id:
|
19
|
-
measure_id:
|
20
|
-
hqmf_id:
|
21
|
-
hqmf_set_id:
|
22
|
-
hqmf_version_number:
|
23
|
-
cms_id:
|
24
|
-
title:
|
25
|
-
description:
|
26
|
-
type:
|
27
|
-
category: { type:
|
18
|
+
id: String,
|
19
|
+
measure_id: String,
|
20
|
+
hqmf_id: String,
|
21
|
+
hqmf_set_id: String,
|
22
|
+
hqmf_version_number: Number,
|
23
|
+
cms_id: String,
|
24
|
+
title: String,
|
25
|
+
description: String,
|
26
|
+
type: String,
|
27
|
+
category: { type: String, default: 'Uncategorized' },
|
28
28
|
|
29
29
|
// Measure type variables
|
30
|
-
episode_of_care:
|
31
|
-
continuous_constiable:
|
30
|
+
episode_of_care: Boolean,
|
31
|
+
continuous_constiable: Boolean,
|
32
32
|
episode_ids: [],
|
33
33
|
|
34
34
|
// Publishing data (used by Bonnie)
|
35
|
-
published:
|
36
|
-
publish_date:
|
37
|
-
version:
|
35
|
+
published: Boolean,
|
36
|
+
publish_date: Date,
|
37
|
+
version: Number,
|
38
38
|
|
39
39
|
// ELM/CQL Measure-logic related data
|
40
40
|
elm_annotations: Mixed,
|
41
|
-
cql: [
|
41
|
+
cql: [String],
|
42
42
|
elm: [Mixed],
|
43
|
-
main_cql_library:
|
43
|
+
main_cql_library: String,
|
44
44
|
cql_statement_dependencies: Mixed,
|
45
45
|
|
46
46
|
// HQMF/Tacoma-specific Measure-logic related data
|
@@ -97,7 +97,8 @@ PatientSchema.methods.findRecords = function findRecords(profile) {
|
|
97
97
|
let profileStripped;
|
98
98
|
if (profile === 'Patient') {
|
99
99
|
// Requested generic patient info
|
100
|
-
|
100
|
+
const info = { birthDatetime: this.birthDatetime };
|
101
|
+
return [info];
|
101
102
|
} else if (/PatientCharacteristic/.test(profile)) {
|
102
103
|
// Requested a patient characteristic
|
103
104
|
profileStripped = profile.replace(/ *\{[^)]*\} */g, '');
|
@@ -1,7 +1,7 @@
|
|
1
1
|
const mongoose = require('mongoose');
|
2
2
|
const Concept = require('./Concept.js');
|
3
3
|
|
4
|
-
const [
|
4
|
+
const [String, Mixed, ObjectId] = [
|
5
5
|
mongoose.Schema.Types.String,
|
6
6
|
mongoose.Schema.Types.Mixed,
|
7
7
|
mongoose.Schema.Types.ObjectId,
|
@@ -9,9 +9,9 @@ const [mString, Mixed, ObjectId] = [
|
|
9
9
|
|
10
10
|
const ValueSetSchema = mongoose.Schema(
|
11
11
|
{
|
12
|
-
oid:
|
13
|
-
display_name:
|
14
|
-
version:
|
12
|
+
oid: String,
|
13
|
+
display_name: String,
|
14
|
+
version: String,
|
15
15
|
categories: Mixed,
|
16
16
|
|
17
17
|
concepts: [Concept.ConceptSchema],
|
@@ -10,3 +10,5 @@ module.exports.ValueSet = require('./ValueSet.js').ValueSet;
|
|
10
10
|
module.exports.ValueSetSchema = require('./ValueSet.js').ValueSetSchema;
|
11
11
|
module.exports.Concept = require('./Concept.js').Concept;
|
12
12
|
module.exports.ConceptSchema = require('./Concept.js').ConceptSchema;
|
13
|
+
module.exports.IndividualResult = require('./IndividualResult').IndividualResult;
|
14
|
+
module.exports.IndividualResultSchema = require('./IndividualResult').IndividualResultSchema;
|
data/app/models/models.rb
CHANGED
@@ -14,6 +14,7 @@ require_relative 'qdm/tacoma/measure'
|
|
14
14
|
require_relative 'qdm/tacoma/measure_package'
|
15
15
|
require_relative 'qdm/tacoma/valueset'
|
16
16
|
require_relative 'qdm/tacoma/concept'
|
17
|
+
require_relative 'qdm/tacoma/individual_result'
|
17
18
|
|
18
19
|
# Generated models
|
19
20
|
require_relative 'qdm/patient'
|
@@ -47,6 +47,23 @@ module QDM
|
|
47
47
|
serializable_hash(methods: :_type).to_json(options)
|
48
48
|
end
|
49
49
|
|
50
|
+
# Shift all fields that deal with dates by the given value.
|
51
|
+
# Given value should be in seconds. Positive values shift forward, negative
|
52
|
+
# values shift backwards.
|
53
|
+
def shift_dates(seconds)
|
54
|
+
# Iterate over fields
|
55
|
+
fields.keys.each do |field|
|
56
|
+
# Check if field is a DateTime
|
57
|
+
if send(field).is_a? DateTime
|
58
|
+
send(field + '=', (send(field).to_time + seconds.seconds).to_datetime)
|
59
|
+
end
|
60
|
+
# Check if field is an Interval
|
61
|
+
if (send(field).is_a? Interval) || (send(field).is_a? DataElement)
|
62
|
+
send(field + '=', send(field).shift_dates(seconds))
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
50
67
|
class << self
|
51
68
|
# Get the object as it was stored in the database, and instantiate
|
52
69
|
# this custom class from it.
|
@@ -16,6 +16,21 @@ module QDM
|
|
16
16
|
{ low: @low, high: @high, lowClosed: @lowClosed, highClosed: @highClosed, _type: 'QDM::Interval' }
|
17
17
|
end
|
18
18
|
|
19
|
+
# Shift dates by the given value.
|
20
|
+
# Given value should be in seconds. Positive values shift forward, negative
|
21
|
+
# values shift backwards.
|
22
|
+
#
|
23
|
+
# NOTE: This will only shift if @high and @low are DateTimes.
|
24
|
+
def shift_dates(seconds)
|
25
|
+
if (@low.is_a? DateTime) || (@low.is_a? Time)
|
26
|
+
@low = (@low.utc.to_time + seconds.seconds).to_datetime.new_offset(0)
|
27
|
+
end
|
28
|
+
if (@high.is_a? DateTime) || (@high.is_a? Time)
|
29
|
+
@high = (@high.utc.to_time + seconds.seconds).to_datetime.new_offset(0)
|
30
|
+
end
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
19
34
|
class << self
|
20
35
|
# Get the object as it was stored in the database, and instantiate
|
21
36
|
# this custom class from it.
|
@@ -25,6 +40,7 @@ module QDM
|
|
25
40
|
def demongoize(object)
|
26
41
|
return nil unless object
|
27
42
|
object = object.symbolize_keys
|
43
|
+
fix_datetime(object)
|
28
44
|
QDM::Interval.new(object[:low], object[:high], object[:lowClosed], object[:highClosed]) if object.is_a?(Hash)
|
29
45
|
end
|
30
46
|
|
@@ -36,11 +52,18 @@ module QDM
|
|
36
52
|
when QDM::Interval then object.mongoize
|
37
53
|
when Hash
|
38
54
|
object = object.symbolize_keys
|
55
|
+
fix_datetime(object)
|
39
56
|
QDM::Interval.new(object[:low], object[:high], object[:lowClosed], object[:highClosed]).mongoize
|
40
57
|
else object
|
41
58
|
end
|
42
59
|
end
|
43
60
|
|
61
|
+
def fix_datetime(object)
|
62
|
+
# Cast to DateTime if it is a string representing a DateTime
|
63
|
+
object[:low] = DateTime.parse(object[:low]) if (object[:low].is_a? String) && DateTime.parse(object[:low])
|
64
|
+
object[:high] = DateTime.parse(object[:high]) if (object[:high].is_a? String) && DateTime.parse(object[:high])
|
65
|
+
end
|
66
|
+
|
44
67
|
# Converts the object that was supplied to a criteria and converts it
|
45
68
|
# into a database friendly form.
|
46
69
|
def evolve(object)
|
data/app/models/qdm/patient.rb
CHANGED
@@ -29,6 +29,17 @@ module QDM
|
|
29
29
|
dataElements.where(qrdaOid: qrda_oid) || []
|
30
30
|
end
|
31
31
|
|
32
|
+
# Shift all data element fields that deal with dates by the given value.
|
33
|
+
# Given value should be in seconds. Positive values shift forward, negative
|
34
|
+
# values shift backwards.
|
35
|
+
#
|
36
|
+
# Note: This will shift dates of the birthdate and
|
37
|
+
# dates on the data elements that exist on the patient.
|
38
|
+
def shift_dates(seconds)
|
39
|
+
self.birthDatetime = (birthDatetime.utc.to_time + seconds.seconds).to_datetime.new_offset(0)
|
40
|
+
dataElements.each { |element| element.shift_dates(seconds) }
|
41
|
+
end
|
42
|
+
|
32
43
|
# Returns an array of elements that exist on this patient. Optionally
|
33
44
|
# takes a category and/or, which returns all elements of that QDM
|
34
45
|
# category. Example: patient.get_data_elements('encounters')
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module QDM
|
2
|
+
# IndividualResult stores the patient-level (population/clause) results for a patient/measure combination
|
3
|
+
class IndividualResult
|
4
|
+
include Mongoid::Document
|
5
|
+
include Mongoid::Timestamps
|
6
|
+
|
7
|
+
# This is the Mongoid equivalent of the Mongoose "enum" attribute for :state. Throws an error if you try to assign a value that's not in this array.
|
8
|
+
validates_inclusion_of :state, in: %w[queued running complete cancelled failed]
|
9
|
+
|
10
|
+
# Population Attributes
|
11
|
+
field :STRAT, type: Integer
|
12
|
+
field :IPP, type: Integer
|
13
|
+
field :DENOM, type: Integer
|
14
|
+
field :NUMER, type: Integer
|
15
|
+
field :NUMEX, type: Integer
|
16
|
+
field :DENEX, type: Integer
|
17
|
+
field :DENEXCEP, type: Integer
|
18
|
+
field :MSRPOPL, type: Integer
|
19
|
+
field :OBSERV, type: Float
|
20
|
+
field :MSRPOPLEX, type: Integer
|
21
|
+
|
22
|
+
# Result Attributes
|
23
|
+
field :clause_results, type: Hash
|
24
|
+
field :episode_results, type: Hash
|
25
|
+
field :statement_results, type: Hash
|
26
|
+
|
27
|
+
# This field is for application specific information only. If both Bonnie and
|
28
|
+
# Cypress use a common field, it should be made a field on this model,
|
29
|
+
# and not put into extendedData.
|
30
|
+
field :extendedData, type: Hash
|
31
|
+
|
32
|
+
# Calculation state attributes
|
33
|
+
field :state, type: String, default: 'queued'
|
34
|
+
|
35
|
+
# Relations to other model classes
|
36
|
+
belongs_to :measure
|
37
|
+
belongs_to :patient
|
38
|
+
end
|
39
|
+
end
|
@@ -74,7 +74,7 @@ module QDM
|
|
74
74
|
# Relations to other model classes
|
75
75
|
belongs_to :user
|
76
76
|
belongs_to :bundle, class_name: 'HealthDataStandards::CQM::Bundle'
|
77
|
-
has_and_belongs_to_many :
|
77
|
+
has_and_belongs_to_many :patients, inverse_of: nil
|
78
78
|
has_one :package, class_name: 'CqlMeasurePackage', inverse_of: :measure, dependent: :destroy
|
79
79
|
|
80
80
|
scope :by_measure_id, ->(id) { where('measure_id' => id) }
|
data/cqm-models.gemspec
CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = 'cqm-models'
|
7
|
-
spec.version = '0.
|
7
|
+
spec.version = '0.8.0'
|
8
8
|
spec.authors = ['aholmes@mitre.org', 'mokeefe@mitre.org', 'lades@mitre.org']
|
9
9
|
|
10
10
|
spec.summary = 'Mongo models that correspond to the QDM specification.'
|