cqm-models 0.7.7 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Build Status](https://travis-ci.org/projecttacoma/cqm-models.svg?branch=master)](https://travis-ci.org/projecttacoma/cqm-models)
|
2
2
|
[![Gem Version](https://badge.fury.io/rb/cqm-models.svg)](https://badge.fury.io/rb/cqm-models)
|
3
|
+
![NPM](https://img.shields.io/npm/v/cqm-models.svg)
|
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.'
|