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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9ed7947882634a78fa7ab8d84693d49b73f00553
4
- data.tar.gz: bfaac070cd031d3cb5e1ad431c7718ceec80ae24
3
+ metadata.gz: adce07d4828edeec55d0a07a98a55f7cd4ca0e6f
4
+ data.tar.gz: fd48e3958c11556440fa984040a426437fb65823
5
5
  SHA512:
6
- metadata.gz: 37c4e67ed09e024af36f767242370acd207d21e3432e04720f9de5ec870d1df27f5ccfd5c366034e1f1cc29d974d77b598f297c4050c90e8e0cce1555f66d538
7
- data.tar.gz: 8e635c6f718e8a42def5bfb34983cf4184a4f3ebca748ca25d1f82027aa46280739101d3654f1f7df2c4f1111e4bce28ffdb34c46f9af0a1092ba251a7d77e2a
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 [mNumber, mString, mBoolean, Mixed, ObjectId, mDate] = [
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: mString,
19
- measure_id: mString,
20
- hqmf_id: mString,
21
- hqmf_set_id: mString,
22
- hqmf_version_number: mNumber,
23
- cms_id: mString,
24
- title: mString,
25
- description: mString,
26
- type: mString,
27
- category: { type: mString, default: 'Uncategorized' },
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: mBoolean,
31
- continuous_constiable: mBoolean,
30
+ episode_of_care: Boolean,
31
+ continuous_constiable: Boolean,
32
32
  episode_ids: [],
33
33
 
34
34
  // Publishing data (used by Bonnie)
35
- published: mBoolean,
36
- publish_date: mDate,
37
- version: mNumber,
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: [mString],
41
+ cql: [String],
42
42
  elm: [Mixed],
43
- main_cql_library: mString,
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
- return { birthDatetime: this.birthDatetime };
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 [mString, Mixed, ObjectId] = [
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: mString,
13
- display_name: mString,
14
- version: mString,
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)
@@ -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 :records, inverse_of: nil
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.7'
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.'