cqm-models 1.1.1.0 → 2.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8466e14ed7d3500909a79c6efba50d1213ae2682defbb4ba43f74748bfe0328a
4
- data.tar.gz: 48a6f30ce90a0937fdbe904380596bf33ecda6d404342f24df1f13e1b02a9227
3
+ metadata.gz: 453a6d2a2d21dbbccbf15183693d0961004c6d2dc5d6e29cef52dbdeec81d0c9
4
+ data.tar.gz: 0c8a483ca5cc294cb67c98790010e3eb1821a40a4a4f613cdf143bc5d1443122
5
5
  SHA512:
6
- metadata.gz: 0f41eb728b0b7134729f1a02ce4687cc297c22f8aede293c2b0cc292af53a11fe73dc4cd56fe9fcbbb1572c92d5e7a39af2f1c369d0aee07b8fa1eac82356aee
7
- data.tar.gz: 3fe0418d0f56139048524f27af04e04774af8e13ddae2a2b930d4ff5f80ed018b5deb6c9bf5aea026840ded58f716815895dc707211ecbbdb7b9be3a2fcd2d94
6
+ metadata.gz: 4c7776a8b071aea930ea925c36b8074b5bcf25ab30e9ca208020dfb94d6d9c77540e5a437b0b82331ea27949ead287842f36fad20ee94ee5a0b055e60a108a1b
7
+ data.tar.gz: 63eca8a60d51e17c611c85408fc5446670b70b410c74829a5d95af3c4ab3937ea3a4db8736c502f8603d794ee328da5a82f79d402ca5ef31491d90f1f2509ff0
@@ -3,7 +3,7 @@ matrix:
3
3
  - language: ruby
4
4
  cache: bundler
5
5
  rvm:
6
- - 2.4.1
6
+ - 2.4.6
7
7
  services:
8
8
  - mongodb
9
9
  before_install:
@@ -10,20 +10,19 @@ function RecursiveCast(any) {
10
10
  if (any && any.value && any.unit) {
11
11
  return new cql.Quantity(any);
12
12
  }
13
- if (any && any.code && any.codeSystem) {
13
+ if (any && any.code && (any.codeSystemOid || any.system)) {
14
14
  if (typeof any.code === 'undefined') {
15
15
  throw new Error(`Code: ${any} does not have a code`);
16
- } else if (typeof any.codeSystem === 'undefined') {
17
- throw new Error(`Code: ${any} does not have a codeSystem`);
16
+ } else if (typeof any.codeSystemOid === 'undefined' && typeof any.system === 'undefined') {
17
+ throw new Error(`Code: ${any} does not have a code system oid`);
18
18
  }
19
19
 
20
- const val = { code: any.code, codeSystem: any.codeSystem };
20
+ const val = { code: any.code, codeSystemOid: any.codeSystemOid || any.system };
21
21
 
22
22
  val.descriptor = (typeof any.descriptor !== 'undefined') ? any.descriptor : null;
23
- val.codeSystemOid = (typeof any.codeSystemOid !== 'undefined') ? any.codeSystemOid : null;
24
23
  val.version = (typeof any.version !== 'undefined') ? any.version : null;
25
24
 
26
- return new cql.Code(val.code, val.codeSystem, val.version, val.descriptor);
25
+ return new cql.Code(val.code, val.codeSystemOid, val.version, val.descriptor);
27
26
  }
28
27
  if (any && any.low) {
29
28
  const casted = new cql.Interval(any.low, any.high, any.lowClosed, any.highClosed);
@@ -9,20 +9,19 @@ Code.prototype = Object.create(mongoose.SchemaType.prototype);
9
9
  Code.prototype.cast = (code) => {
10
10
  if (code != null) {
11
11
  // handles codes that have not yet been cast to a code and those that have already been cast to a code
12
- if (code.code && (code.codeSystem || code.system)) {
12
+ if (code.code && (code.codeSystemOid || code.system)) {
13
13
  if (typeof code.code === 'undefined') {
14
14
  throw new Error(`Code: ${code} does not have a code`);
15
- } else if (typeof code.codeSystem === 'undefined' && typeof code.system === 'undefined') {
16
- throw new Error(`Code: ${code} does not have a system`);
15
+ } else if (typeof code.codeSystemOid === 'undefined' && typeof code.system === 'undefined') {
16
+ throw new Error(`Code: ${code} does not have a system oid`);
17
17
  }
18
18
 
19
- const val = { code: code.code, codeSystem: code.codeSystem || code.system };
19
+ const val = { code: code.code, codeSystemOid: code.codeSystemOid || code.system };
20
20
 
21
21
  val.descriptor = (typeof code.descriptor !== 'undefined') ? code.descriptor : null;
22
- val.codeSystemOid = (typeof code.codeSystemOid !== 'undefined') ? code.codeSystemOid : null;
23
22
  val.version = (typeof code.version !== 'undefined') ? code.version : null;
24
23
 
25
- return new cql.Code(val.code, val.codeSystem, val.version, val.descriptor);
24
+ return new cql.Code(val.code, val.codeSystemOid, val.version, val.descriptor);
26
25
  }
27
26
  throw new Error(`Expected a code. Received ${code}.`);
28
27
  } else {
@@ -25,7 +25,7 @@ function DataElementSchema(add, options) {
25
25
  // Returns all of the codes on this data element in a format usable by
26
26
  // the cql-execution framework.
27
27
  extended.methods.getCode = function getCode() {
28
- return this.dataElementCodes.map(code => new cql.Code(code.code, code.codeSystem, code.version, code.descriptor));
28
+ return this.dataElementCodes.map(code => new cql.Code(code.code, code.codeSystemOid, code.version, code.descriptor));
29
29
  };
30
30
 
31
31
  // Return the first code on this data element in a format usable by
@@ -33,7 +33,7 @@ function DataElementSchema(add, options) {
33
33
  extended.methods.code = function code() {
34
34
  if (this.dataElementCodes && this.dataElementCodes[0]) {
35
35
  const qdmCode = this.dataElementCodes[0];
36
- return new cql.Code(qdmCode.code, qdmCode.codeSystem, qdmCode.version, qdmCode.descriptor);
36
+ return new cql.Code(qdmCode.code, qdmCode.codeSystemOid, qdmCode.version, qdmCode.descriptor);
37
37
  }
38
38
  return null;
39
39
  };
@@ -1,5 +1,6 @@
1
1
  const mongoose = require('mongoose/browser');
2
2
  const cql = require('cql-execution');
3
+ const DateTime = require('./DateTime');
3
4
 
4
5
  function Interval(key, options) {
5
6
  mongoose.SchemaType.call(this, key, options, 'Interval');
@@ -7,8 +8,8 @@ function Interval(key, options) {
7
8
  Interval.prototype = Object.create(mongoose.SchemaType.prototype);
8
9
 
9
10
  Interval.prototype.cast = (interval) => {
10
- if (typeof interval.low === 'undefined' || interval.low === null) {
11
- throw new Error(`Interval: ${interval} does not have a low value`);
11
+ if (interval.isInterval) {
12
+ return interval;
12
13
  }
13
14
  const casted = new cql.Interval(interval.low, interval.high, interval.lowClosed, interval.highClosed);
14
15
 
@@ -22,11 +23,12 @@ Interval.prototype.cast = (interval) => {
22
23
  }
23
24
 
24
25
  // Cast to DateTime if it is a string representing a DateTime
25
- if (casted.low && Date.parse(casted.low)) {
26
- casted.low = cql.DateTime.fromJSDate(new Date(casted.low), 0);
26
+ if (casted.low) {
27
+ casted.low = DateTime.prototype.cast(casted.low);
27
28
  }
28
- if (casted.high && Date.parse(casted.high)) {
29
- casted.high = cql.DateTime.fromJSDate(new Date(casted.high), 0);
29
+
30
+ if (casted.high) {
31
+ casted.high = DateTime.prototype.cast(casted.high);
30
32
  }
31
33
  return casted;
32
34
  };
@@ -22,3 +22,5 @@ module.exports.Patient = require('./Patient.js').Patient;
22
22
  module.exports.PatientSchema = require('./Patient.js').PatientSchema;
23
23
  module.exports.Provider = require('./Provider.js').Provider;
24
24
  module.exports.ProviderSchema = require('./Provider.js').ProviderSchema;
25
+ module.exports.IndividualResult = require('./IndividualResult.js').IndividualResult;
26
+ module.exports.IndividualResultSchema = require('./IndividualResult.js').IndividualResultSchema;
@@ -0,0 +1,28 @@
1
+ const mongoose = require('mongoose/browser');
2
+
3
+ const [String, Mixed] = [
4
+ mongoose.Schema.Types.String,
5
+ mongoose.Schema.Types.Mixed,
6
+ ];
7
+
8
+ const ClauseResultSchema = mongoose.Schema({
9
+ // Library the clause this result is for is in
10
+ library_name: String,
11
+ // Statement the clause this result is for is in
12
+ statement_name: String,
13
+ // LocalId of the clause this result is for
14
+ localId: String,
15
+ // Final, processed result of raw calculation
16
+ final: String,
17
+ // Raw result of clause calculation
18
+ raw: Mixed,
19
+ });
20
+
21
+
22
+ module.exports.ClauseResultSchema = ClauseResultSchema;
23
+ class ClauseResult extends mongoose.Document {
24
+ constructor(object) {
25
+ super(object, ClauseResultSchema);
26
+ }
27
+ }
28
+ module.exports.ClauseResult = ClauseResult;
@@ -1,4 +1,6 @@
1
1
  const mongoose = require('mongoose/browser');
2
+ const { ClauseResultSchema } = require('./ClauseResult');
3
+ const { StatementResultSchema } = require('./StatementResult');
2
4
 
3
5
  const [Number, String, Mixed, ObjectId] = [
4
6
  mongoose.Schema.Types.Number,
@@ -22,9 +24,11 @@ const IndividualResultSchema = mongoose.Schema(
22
24
  MSRPOPLEX: Number,
23
25
 
24
26
  // Result Attributes
25
- clause_results: Mixed,
27
+ clause_results: [ClauseResultSchema],
28
+ statement_results: [StatementResultSchema],
29
+ population_relevance: Mixed,
26
30
  episode_results: Mixed,
27
- statement_results: Mixed,
31
+ observation_values: [Number],
28
32
 
29
33
  // This field is for application specific information only. If both Bonnie and
30
34
  // Cypress use a common field, it should be made a field on this model,
@@ -53,6 +57,28 @@ const IndividualResultSchema = mongoose.Schema(
53
57
  }
54
58
  );
55
59
 
60
+ IndividualResultSchema.methods.clause_results_by_clause = function clause_results_by_clause() {
61
+ const clause_results_hash = {};
62
+ this.clause_results.forEach((result) => {
63
+ if (!clause_results_hash[result.library_name]) {
64
+ clause_results_hash[result.library_name] = {};
65
+ }
66
+ clause_results_hash[result.library_name][result.localId] = result;
67
+ });
68
+ return clause_results_hash;
69
+ };
70
+
71
+ IndividualResultSchema.methods.statement_results_by_statement = function statement_results_by_statement() {
72
+ const statement_results_hash = {};
73
+ this.statement_results.forEach((result) => {
74
+ if (!statement_results_hash[result.library_name]) {
75
+ statement_results_hash[result.library_name] = {};
76
+ }
77
+ statement_results_hash[result.library_name][result.statement_name] = result;
78
+ });
79
+ return statement_results_hash;
80
+ };
81
+
56
82
  module.exports.IndividualResultSchema = IndividualResultSchema;
57
83
  class IndividualResult extends mongoose.Document {
58
84
  constructor(object) {
@@ -64,7 +64,7 @@ const MeasureSchema = new mongoose.Schema(
64
64
  // HQMF/Tacoma-specific Measure-logic related data
65
65
  population_criteria: Mixed,
66
66
  source_data_criteria: [],
67
- measure_period: Interval,
67
+ measure_period: Mixed,
68
68
  measure_attributes: [],
69
69
 
70
70
  population_sets: [PopulationSetSchema],
@@ -0,0 +1,41 @@
1
+ const mongoose = require('mongoose/browser');
2
+
3
+ const [String, Mixed] = [
4
+ mongoose.Schema.Types.String,
5
+ mongoose.Schema.Types.Mixed,
6
+ ];
7
+
8
+ const StatementResultSchema = mongoose.Schema({
9
+ // Library the statement this result is for is in
10
+ library_name: String,
11
+ // Statement this result is for is in
12
+ statement_name: String,
13
+ // Result, processed for display, of the statement this result is for
14
+ pretty: String,
15
+ // Final, processed result of raw calculation
16
+ final: String,
17
+ // Raw result of clause calculation
18
+ raw: Mixed,
19
+ /*
20
+ * 'NA' - Not applicable. This statement is not relevant to any population calculation in this population_set. Common
21
+ * for unused library statements or statements only used for other population sets.
22
+ *
23
+ * 'FALSE' - This statement is not relevant to any of this patient's population inclusion calculations.
24
+ *
25
+ * 'TRUE' - This statement is relevant for one or more of the population inclusion calculations.
26
+ */
27
+ relevance: {
28
+ type: String,
29
+ enum: ['NA', 'TRUE', 'FALSE'],
30
+ default: 'NA',
31
+ },
32
+ });
33
+
34
+
35
+ module.exports.StatementResultSchema = StatementResultSchema;
36
+ class StatementResult extends mongoose.Document {
37
+ constructor(object) {
38
+ super(object, StatementResultSchema);
39
+ }
40
+ }
41
+ module.exports.StatementResult = StatementResult;
@@ -20,5 +20,9 @@ module.exports.ValueSet = require('./cqm/ValueSet.js').ValueSet;
20
20
  module.exports.ValueSetSchema = require('./cqm/ValueSet.js').ValueSetSchema;
21
21
  module.exports.Concept = require('./cqm/Concept.js').Concept;
22
22
  module.exports.ConceptSchema = require('./cqm/Concept.js').ConceptSchema;
23
- module.exports.IndividualResult = require('./IndividualResult').IndividualResult;
24
- module.exports.IndividualResultSchema = require('./IndividualResult').IndividualResultSchema;
23
+ module.exports.IndividualResult = require('./cqm/IndividualResult.js').IndividualResult;
24
+ module.exports.IndividualResultSchema = require('./cqm/IndividualResult.js').IndividualResultSchema;
25
+ module.exports.ClauseResult = require('./cqm/ClauseResult.js').ClauseResult;
26
+ module.exports.ClauseResultSchema = require('./cqm/ClauseResult.js').ClauseResultSchema;
27
+ module.exports.StatementResult = require('./cqm/StatementResult.js').StatementResult;
28
+ module.exports.StatementResultSchema = require('./cqm/StatementResult.js').StatementResultchema;
@@ -0,0 +1,21 @@
1
+ module CQM
2
+ # ClauseResult is used to store clause result information in IndividualResult
3
+ class ClauseResult
4
+ include Mongoid::Document
5
+ include Mongoid::Timestamps
6
+
7
+ # Library the clause this result is for is in
8
+ field :library_name, type: String
9
+ # Statment the clause this result is for is in
10
+ field :statement_name, type: String
11
+ # LocalId of the clause this result is for
12
+ field :localId, type: String
13
+ # Final, processed result of raw calculation
14
+ field :final, type: String
15
+ # Raw result of clause calculation
16
+ field :raw
17
+
18
+ # Relations to other model classes
19
+ embedded_in :individual_result
20
+ end
21
+ end
@@ -1,4 +1,4 @@
1
- module QDM
1
+ module CQM
2
2
  # IndividualResult stores the patient-level (population/clause) results for a patient/measure combination
3
3
  class IndividualResult
4
4
  include Mongoid::Document
@@ -20,9 +20,11 @@ module QDM
20
20
  field :MSRPOPLEX, type: Integer
21
21
 
22
22
  # Result Attributes
23
- field :clause_results, type: Hash
23
+ embeds_many :clause_results
24
+ embeds_many :statement_results
24
25
  field :episode_results, type: Hash
25
- field :statement_results, type: Hash
26
+ field :observation_values, type: Array, default: []
27
+ field :population_relevance, type: Hash
26
28
 
27
29
  # This field is for application specific information only. If both Bonnie and
28
30
  # Cypress use a common field, it should be made a field on this model,
@@ -35,5 +37,28 @@ module QDM
35
37
  # Relations to other model classes
36
38
  belongs_to :measure
37
39
  belongs_to :patient
40
+
41
+ # Convert the stored array into a hash between clause and result
42
+ def clause_results_by_clause
43
+ clause_results_hash = {}
44
+ clause_results.each do |result|
45
+ unless clause_results_hash[result['library_name']]
46
+ clause_results_hash[result['library_name']] = {}
47
+ end
48
+ clause_results_hash[result['library_name']][result['localId']] = result
49
+ end
50
+ return clause_results_hash
51
+ end
52
+
53
+ def statement_results_by_statement
54
+ statement_results_hash = {}
55
+ statement_results.each do |result|
56
+ unless statement_results_hash[result['library_name']]
57
+ statement_results_hash[result['library_name']] = {}
58
+ end
59
+ statement_results_hash[result['library_name']][result['statement_name']] = result
60
+ end
61
+ return statement_results_hash
62
+ end
38
63
  end
39
64
  end
@@ -73,6 +73,8 @@ module CQM
73
73
  # hence the 'inverse_of: nil')
74
74
  has_and_belongs_to_many :value_sets, inverse_of: nil
75
75
 
76
+ has_many :calculation_results, class_name: 'CQM::IndividualResult'
77
+
76
78
  def all_stratifications
77
79
  population_sets.flat_map(&:stratifications)
78
80
  end
@@ -11,6 +11,7 @@ module CQM
11
11
 
12
12
  has_and_belongs_to_many :providers, class_name: 'CQM::Provider'
13
13
  embeds_one :qdmPatient, class_name: 'QDM::Patient', autobuild: true
14
+ has_many :calculation_results, class_name: 'CQM::IndividualResult'
14
15
 
15
16
  # Include '_type' in any JSON output. This is necessary for deserialization.
16
17
  def to_json(options = nil)
@@ -0,0 +1,27 @@
1
+ module CQM
2
+ # StatementResult is used to store statement result information in IndividualResult
3
+ class StatementResult
4
+ include Mongoid::Document
5
+ include Mongoid::Timestamps
6
+
7
+ # These are the Mongoid equivalent of the Mongoose "enum" attribute for the respective fields.
8
+ # They throw an error if you try to assign a value that's not in the array.
9
+ validates_inclusion_of :relevance, in: %w[NA TRUE FALSE]
10
+
11
+ # Library the clause this result is for is in
12
+ field :library_name, type: String
13
+ # Statment the clause this result is for is in
14
+ field :statement_name, type: String
15
+ # LocalId of the clause this result is for
16
+ field :pretty, type: String
17
+ # Final, processed result of raw calculation
18
+ field :final, type: String
19
+ # Raw result of clause calculation
20
+ field :raw
21
+
22
+ field :relevance, type: String
23
+
24
+ # Relations to other model classes
25
+ embedded_in :individual_result
26
+ end
27
+ end
@@ -29,7 +29,9 @@ require_relative 'cqm/cql_library'
29
29
  require_relative 'cqm/population_set'
30
30
  require_relative 'cqm/patient'
31
31
  require_relative 'cqm/provider'
32
- require_relative 'qdm/tacoma/individual_result'
32
+ require_relative 'cqm/individual_result'
33
+ require_relative 'cqm/statement_result'
34
+ require_relative 'cqm/clause_result'
33
35
 
34
36
  # Make Patient Generation Available
35
37
  require_relative '../../lib/generate_patients'
@@ -4,7 +4,7 @@ module QDM
4
4
  attr_accessor :code, :codeSystem, :descriptor, :codeSystemOid, :version
5
5
 
6
6
  # Code and code system are required (at minimum).
7
- def initialize(code, codeSystem, descriptor = nil, codeSystemOid = nil, version = nil)
7
+ def initialize(code, codeSystemOid, descriptor = nil, codeSystem = nil, version = nil)
8
8
  @code = code
9
9
  @codeSystem = codeSystem
10
10
  @descriptor = descriptor
@@ -14,7 +14,7 @@ module QDM
14
14
 
15
15
  # Converts an object of this instance into a database friendly value.
16
16
  def mongoize
17
- { code: @code, codeSystem: @codeSystem, descriptor: @descriptor, codeSystemOid: @codeSystemOid, version: @version, _type: 'QDM::Code' }
17
+ { code: @code, codeSystemOid: @codeSystemOid, descriptor: @descriptor, codeSystem: @codeSystem, version: @version, _type: 'QDM::Code' }
18
18
  end
19
19
 
20
20
  class << self
@@ -26,7 +26,7 @@ module QDM
26
26
  def demongoize(object)
27
27
  return nil unless object
28
28
  object = object.symbolize_keys
29
- QDM::Code.new(object[:code], object[:codeSystem], object[:descriptor], object[:codeSystemOid], object[:version])
29
+ QDM::Code.new(object[:code], object[:codeSystemOid], object[:descriptor], object[:codeSystem], object[:version])
30
30
  end
31
31
 
32
32
  # Takes any possible object and converts it to how it would be
@@ -37,8 +37,8 @@ module QDM
37
37
  when QDM::Code then object.mongoize
38
38
  when Hash
39
39
  object = object.symbolize_keys
40
- codeSystem = object[:system] ? object[:system] : object[:codeSystem]
41
- QDM::Code.new(object[:code], codeSystem, object[:descriptor], object[:codeSystemOid], object[:version]).mongoize
40
+ codeSystemOid = object[:system] ? object[:system] : object[:codeSystemOid]
41
+ QDM::Code.new(object[:code], codeSystemOid, object[:descriptor], object[:codeSystem], object[:version]).mongoize
42
42
  else object
43
43
  end
44
44
  end